Repository: Azure/azure-mobile-services
Branch: master
Commit: 1198c8576bf1
Files: 1814
Total size: 17.4 MB
Directory structure:
gitextract_8ud35due/
├── .gitattributes
├── .gitignore
├── .gitmodules
├── CHANGELOG.android.md
├── CHANGELOG.ios.md
├── CHANGELOG.javascript.md
├── CHANGELOG.managed.md
├── CHANGELOG.md
├── LICENSE.txt
├── README.md
├── component/
│ ├── .gitignore
│ ├── Details.md
│ ├── GettingStarted.md
│ ├── License.md
│ ├── component.yaml
│ ├── icon.psd
│ └── samples/
│ ├── androidsample/
│ │ ├── androidsample/
│ │ │ ├── Assets/
│ │ │ │ └── AboutAssets.txt
│ │ │ ├── Properties/
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ └── AssemblyInfo.cs
│ │ │ ├── Resources/
│ │ │ │ ├── AboutResources.txt
│ │ │ │ ├── Resource.designer.cs
│ │ │ │ ├── layout/
│ │ │ │ │ ├── Activity_To_Do.axml
│ │ │ │ │ └── Row_List_To_Do.axml
│ │ │ │ ├── menu/
│ │ │ │ │ └── activity_main.xml
│ │ │ │ ├── values/
│ │ │ │ │ ├── Strings.xml
│ │ │ │ │ └── styles.xml
│ │ │ │ ├── values-v11/
│ │ │ │ │ └── styles.xml
│ │ │ │ └── values-v14/
│ │ │ │ └── styles.xml
│ │ │ ├── ToDoActivity.cs
│ │ │ ├── ToDoItem.cs
│ │ │ ├── ToDoItemAdapter.cs
│ │ │ ├── androidsample.csproj
│ │ │ └── app.config
│ │ └── androidsample.sln
│ └── iOSsample/
│ ├── iOSsample/
│ │ ├── AppDelegate.cs
│ │ ├── Info.plist
│ │ ├── Main.cs
│ │ ├── MainStoryboard_iPad.storyboard
│ │ ├── MainStoryboard_iPhone.storyboard
│ │ ├── QSTodoListViewController.cs
│ │ ├── QSTodoListViewController.designer.cs
│ │ ├── QSTodoService.cs
│ │ ├── ToDoItem.cs
│ │ ├── app.config
│ │ └── iOSsample.csproj
│ └── iOSsample.sln
├── docs/
│ ├── README.md
│ ├── mobile-services-android-get-started-data.md
│ ├── mobile-services-android-get-started-offline-data.md
│ ├── mobile-services-android-get-started-users.md
│ ├── mobile-services-android-get-started.md
│ ├── mobile-services-android-how-to-use-client-library.md
│ ├── mobile-services-android-upload-data-blob-storage.md
│ ├── mobile-services-concepts-links.md
│ ├── mobile-services-disaster-recovery.md
│ ├── mobile-services-dotnet-backend-android-get-started-push.md
│ ├── mobile-services-dotnet-backend-android-get-started-users.md
│ ├── mobile-services-dotnet-backend-android-get-started.md
│ ├── mobile-services-dotnet-backend-define-custom-api.md
│ ├── mobile-services-dotnet-backend-get-started-custom-authentication.md
│ ├── mobile-services-dotnet-backend-how-to-configure-iis-express.md
│ ├── mobile-services-dotnet-backend-how-to-troubleshoot.md
│ ├── mobile-services-dotnet-backend-how-to-use-code-first-migrations.md
│ ├── mobile-services-dotnet-backend-hybrid-connections-get-started.md
│ ├── mobile-services-dotnet-backend-ios-adal-sso-authentication.md
│ ├── mobile-services-dotnet-backend-ios-get-started-push.md
│ ├── mobile-services-dotnet-backend-ios-get-started-users.md
│ ├── mobile-services-dotnet-backend-ios-get-started.md
│ ├── mobile-services-dotnet-backend-ios-push-notifications-app-users.md
│ ├── mobile-services-dotnet-backend-schedule-recurring-tasks.md
│ ├── mobile-services-dotnet-backend-service-side-authorization.md
│ ├── mobile-services-dotnet-backend-store-code-source-control.md
│ ├── mobile-services-dotnet-backend-store-data-table-storage.md
│ ├── mobile-services-dotnet-backend-use-existing-sql-database.md
│ ├── mobile-services-dotnet-backend-windows-store-dotnet-aad-rbac.md
│ ├── mobile-services-dotnet-backend-windows-store-dotnet-get-started.md
│ ├── mobile-services-dotnet-backend-windows-store-dotnet-leaderboard.md
│ ├── mobile-services-dotnet-backend-windows-store-dotnet-push-notifications-app-users.md
│ ├── mobile-services-dotnet-backend-windows-universal-dotnet-get-started-data.md
│ ├── mobile-services-dotnet-backend-windows-universal-dotnet-get-started-push.md
│ ├── mobile-services-dotnet-backend-windows-universal-dotnet-get-started-users.md
│ ├── mobile-services-dotnet-backend-windows-universal-dotnet-upload-data-blob-storage.md
│ ├── mobile-services-dotnet-backend-xamarin-android-get-started-push.md
│ ├── mobile-services-dotnet-backend-xamarin-android-get-started-users.md
│ ├── mobile-services-dotnet-backend-xamarin-android-get-started.md
│ ├── mobile-services-dotnet-backend-xamarin-ios-get-started-users.md
│ ├── mobile-services-dotnet-backend-xamarin-ios-get-started.md
│ ├── mobile-services-dotnet-how-to-use-client-library.md
│ ├── mobile-services-how-to-register-active-directory-authentication.md
│ ├── mobile-services-how-to-register-facebook-authentication.md
│ ├── mobile-services-how-to-register-google-authentication.md
│ ├── mobile-services-how-to-register-microsoft-authentication.md
│ ├── mobile-services-how-to-register-twitter-authentication.md
│ ├── mobile-services-how-to-use-multiple-clients-single-service.md
│ ├── mobile-services-how-to-use-server-scripts.md
│ ├── mobile-services-html-get-started-users.md
│ ├── mobile-services-html-get-started.md
│ ├── mobile-services-html-how-to-use-client-library.md
│ ├── mobile-services-ios-get-started-offline-data.md
│ ├── mobile-services-ios-get-started-users.md
│ ├── mobile-services-ios-get-started.md
│ ├── mobile-services-ios-handling-conflicts-offline-data.md
│ ├── mobile-services-ios-how-to-use-client-library.md
│ ├── mobile-services-javascript-backend-android-get-started-push.md
│ ├── mobile-services-javascript-backend-define-custom-api.md
│ ├── mobile-services-javascript-backend-ios-get-started-push.md
│ ├── mobile-services-javascript-backend-ios-push-notifications-app-users.md
│ ├── mobile-services-javascript-backend-phonegap-get-started.md
│ ├── mobile-services-javascript-backend-service-side-authorization.md
│ ├── mobile-services-javascript-backend-windows-phone-get-started-push.md
│ ├── mobile-services-javascript-backend-windows-store-dotnet-get-started.md
│ ├── mobile-services-javascript-backend-windows-store-dotnet-push-notifications-app-users.md
│ ├── mobile-services-javascript-backend-windows-store-javascript-get-started.md
│ ├── mobile-services-javascript-backend-windows-universal-dotnet-get-started-push.md
│ ├── mobile-services-javascript-backend-windows-universal-dotnet-get-started-users.md
│ ├── mobile-services-javascript-backend-windows-universal-dotnet-upload-data-blob-storage.md
│ ├── mobile-services-manage-command-line-interface.md
│ ├── mobile-services-schedule-recurring-tasks.md
│ ├── mobile-services-sql-scale-guidance.md
│ ├── mobile-services-store-scripts-source-control.md
│ ├── mobile-services-using-soft-delete.md
│ ├── mobile-services-windows-phone-get-started-data.md
│ ├── mobile-services-windows-phone-get-started-users.md
│ ├── mobile-services-windows-store-dotnet-adal-sso-authentication.md
│ ├── mobile-services-windows-store-dotnet-get-started-offline-data.md
│ ├── mobile-services-windows-store-dotnet-handle-database-conflicts.md
│ ├── mobile-services-windows-store-dotnet-handling-conflicts-offline-data.md
│ ├── mobile-services-xamarin-android-get-started-offline-data.md
│ ├── mobile-services-xamarin-ios-get-started-offline-data.md
│ ├── partner-sencha-mobile-services-get-started.md
│ ├── partner-twilio-mobile-services-how-to-use-voice-sms.md
│ ├── partner-xamarin-mobile-services-android-get-started-push.md
│ ├── partner-xamarin-mobile-services-android-get-started-users.md
│ ├── partner-xamarin-mobile-services-android-get-started.md
│ ├── partner-xamarin-mobile-services-ios-get-started-push.md
│ ├── partner-xamarin-mobile-services-ios-get-started-users.md
│ ├── partner-xamarin-mobile-services-ios-get-started.md
│ ├── partner-xamarin-mobile-services-xamarin-forms-get-started-push.md
│ ├── store-sendgrid-mobile-services-send-email-scripts.md
│ ├── vs-mobile-services-cordova-getting-started.md
│ ├── vs-mobile-services-cordova-what-happened.md
│ ├── vs-mobile-services-dotnet-getting-started.md
│ ├── vs-mobile-services-dotnet-what-happened.md
│ ├── vs-mobile-services-javascript-getting-started.md
│ └── vs-mobile-services-javascript-what-happened.md
├── sdk/
│ ├── Javascript/
│ │ ├── .gitignore
│ │ ├── Gruntfile.js
│ │ ├── Microsoft.WindowsAzure.Mobile.JS.sln
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── Generated/
│ │ │ │ └── .gitignore
│ │ │ ├── Internals/
│ │ │ │ ├── DevIntellisense.js
│ │ │ │ ├── InternalsVisible.js
│ │ │ │ └── NodeExports.js
│ │ │ ├── LoginUis/
│ │ │ │ ├── BrowserPopup.js
│ │ │ │ ├── CordovaPopup.js
│ │ │ │ └── WebAuthBroker.js
│ │ │ ├── Microsoft.WindowsAzure.Mobile.JS.csproj
│ │ │ ├── MobileServiceClient.js
│ │ │ ├── MobileServiceLogin.js
│ │ │ ├── MobileServiceTable.js
│ │ │ ├── MobileServices.intellisense.js
│ │ │ ├── MobileServices.intellisense.txt
│ │ │ ├── MobileServices.priconfig.xml
│ │ │ ├── Platforms/
│ │ │ │ ├── Platform.Web.js
│ │ │ │ └── Platform.WinJS.js
│ │ │ ├── Properties/
│ │ │ │ └── AssemblyInfo.cs
│ │ │ ├── Push/
│ │ │ │ ├── LocalStorageManager.js
│ │ │ │ ├── Push.Web.js
│ │ │ │ ├── Push.WinJS.js
│ │ │ │ ├── PushHttpClient.js
│ │ │ │ └── RegistrationManager.js
│ │ │ ├── Require.js
│ │ │ ├── Strings/
│ │ │ │ └── en-US/
│ │ │ │ └── Resources.resjson
│ │ │ ├── Transports/
│ │ │ │ ├── DirectAjaxTransport.js
│ │ │ │ └── IframeTransport.js
│ │ │ └── Utilities/
│ │ │ ├── Extensions.js
│ │ │ ├── PostMessageExchange.js
│ │ │ ├── Promises.js
│ │ │ └── Validate.js
│ │ ├── test/
│ │ │ ├── framework/
│ │ │ │ ├── ActionContinuation.cs
│ │ │ │ ├── Assert.cs
│ │ │ │ ├── FunctionalTestFilter.cs
│ │ │ │ ├── IAsyncExecution.cs
│ │ │ │ ├── IContinuation.cs
│ │ │ │ ├── ITestReporter.cs
│ │ │ │ ├── Microsoft.WindowsAzure.Mobile.WinJS.TestFramework.csproj
│ │ │ │ ├── Properties/
│ │ │ │ │ └── AssemblyInfo.cs
│ │ │ │ ├── RuntimeTestFilter.cs
│ │ │ │ ├── Tagging/
│ │ │ │ │ ├── TagManager.ExpressionEvaluator.cs
│ │ │ │ │ ├── TagManager.Tags.cs
│ │ │ │ │ ├── TagManager.cs
│ │ │ │ │ └── TagTestFilter.cs
│ │ │ │ ├── TestFilter.cs
│ │ │ │ ├── TestGroup.cs
│ │ │ │ ├── TestHarness.cs
│ │ │ │ ├── TestMethod.cs
│ │ │ │ ├── TestSettings.cs
│ │ │ │ └── WinJS/
│ │ │ │ ├── Formatter.cs
│ │ │ │ ├── MessageEventArgs.cs
│ │ │ │ ├── PromiseAsyncExecution.cs
│ │ │ │ ├── PromiseAsyncExecutionEventArgs.cs
│ │ │ │ └── TestReporter.cs
│ │ │ ├── web/
│ │ │ │ ├── Microsoft.Azure.Zumo.Web.Test.csproj
│ │ │ │ ├── Tests.library
│ │ │ │ ├── Web.Debug.config
│ │ │ │ ├── Web.Release.config
│ │ │ │ ├── Web.config
│ │ │ │ ├── css/
│ │ │ │ │ └── styles.css
│ │ │ │ ├── generated/
│ │ │ │ │ └── .gitignore
│ │ │ │ ├── index.html
│ │ │ │ ├── js/
│ │ │ │ │ ├── TestClientHelper.js
│ │ │ │ │ └── TestFrameworkAdapter.js
│ │ │ │ ├── promiseTests/
│ │ │ │ │ ├── package.json
│ │ │ │ │ ├── readme.txt
│ │ │ │ │ └── test-promises.js
│ │ │ │ └── tests/
│ │ │ │ └── unit/
│ │ │ │ └── push.js
│ │ │ └── winJS/
│ │ │ ├── Microsoft.Azure.Zumo.Windows.WinJS.Test_TemporaryKey.pfx
│ │ │ ├── Microsoft.WindowsAzure.Mobile.WinJS.Test.jsproj
│ │ │ ├── Tests.library
│ │ │ ├── css/
│ │ │ │ └── default.css
│ │ │ ├── default.html
│ │ │ ├── generated/
│ │ │ │ └── .gitignore
│ │ │ ├── js/
│ │ │ │ └── default.js
│ │ │ ├── package.appxmanifest
│ │ │ ├── packages.config
│ │ │ └── tests/
│ │ │ ├── TestFramework.js
│ │ │ ├── TestInterface.js
│ │ │ ├── functional/
│ │ │ │ ├── basics.js
│ │ │ │ ├── blogging.js
│ │ │ │ ├── dates.js
│ │ │ │ ├── mobileServiceTable.Functional.js
│ │ │ │ └── todo.js
│ │ │ ├── unit/
│ │ │ │ ├── extensions.js
│ │ │ │ ├── localStorageManager.js
│ │ │ │ ├── mobileServiceTables.js
│ │ │ │ ├── mobileServicesClient._request.js
│ │ │ │ ├── mobileServicesClient.js
│ │ │ │ ├── pushHttpClient.js
│ │ │ │ ├── registrationManager.js
│ │ │ │ └── validate.js
│ │ │ ├── utilities/
│ │ │ │ ├── TableHelper.js
│ │ │ │ └── constants.js
│ │ │ └── winJsOnly/
│ │ │ └── push.js
│ │ └── tools/
│ │ └── JSBuild/
│ │ ├── MergeJSModules.cs
│ │ ├── Microsoft.WindowsAzure.Mobile.JSBuild.csproj
│ │ └── Properties/
│ │ └── AssemblyInfo.cs
│ ├── Managed/
│ │ ├── .gitignore
│ │ ├── Microsoft.WindowsAzure.Mobile.Managed - IncludeXamarin.sln
│ │ ├── Microsoft.WindowsAzure.Mobile.Managed.SQLiteStore.sln
│ │ ├── Microsoft.WindowsAzure.Mobile.Managed.sln
│ │ ├── src/
│ │ │ ├── Microsoft.WindowsAzure.MobileServices/
│ │ │ │ ├── Authentication/
│ │ │ │ │ ├── MobileServiceAuthentication.cs
│ │ │ │ │ ├── MobileServiceAuthenticationProvider.cs
│ │ │ │ │ └── MobileServiceTokenAuthentication.cs
│ │ │ │ ├── Collections/
│ │ │ │ │ ├── MobileServiceCollection.cs
│ │ │ │ │ └── MobileServiceCollectionEventArgs.cs
│ │ │ │ ├── EnumValueAttribute.cs
│ │ │ │ ├── Exceptions/
│ │ │ │ │ ├── MobileServiceConflictException.cs
│ │ │ │ │ ├── MobileServiceInvalidOperationException.cs
│ │ │ │ │ ├── MobileServiceLocalStoreException.cs
│ │ │ │ │ ├── MobileServiceODataException.cs
│ │ │ │ │ ├── MobileServicePreconditionFailedException.cs
│ │ │ │ │ ├── MobileServicePushAbortException.cs
│ │ │ │ │ └── MobileServicePushFailedException.cs
│ │ │ │ ├── Extensions/
│ │ │ │ │ ├── ExceptionExtensions.cs
│ │ │ │ │ ├── IDictionaryExtensions.cs
│ │ │ │ │ ├── JTokenExtensions.cs
│ │ │ │ │ ├── MobileServiceClientExtensions.cs
│ │ │ │ │ ├── MobileServiceCollectionExtensions.cs
│ │ │ │ │ ├── MobileServiceLocalStoreExtensions.cs
│ │ │ │ │ ├── MobileServiceSyncContextExtensions.cs
│ │ │ │ │ ├── MobileServiceSyncTableExtensions.cs
│ │ │ │ │ ├── MobileServiceTableExtensions.cs
│ │ │ │ │ ├── PlatformInformationExtensions.cs
│ │ │ │ │ ├── StringExtensions.cs
│ │ │ │ │ └── TypeExtensions.cs
│ │ │ │ ├── Http/
│ │ │ │ │ ├── HttpUtility.cs
│ │ │ │ │ ├── LinkHeaderValue.cs
│ │ │ │ │ ├── MobileServiceHttpClient.cs
│ │ │ │ │ └── MobileServiceHttpResponse.cs
│ │ │ │ ├── IMobileServiceClient.cs
│ │ │ │ ├── Microsoft.WindowsAzure.Mobile.csproj
│ │ │ │ ├── MobileServiceClient.cs
│ │ │ │ ├── MobileServiceFeatures.cs
│ │ │ │ ├── MobileServiceUrlBuilder.cs
│ │ │ │ ├── MobileServiceUser.cs
│ │ │ │ ├── Platform/
│ │ │ │ │ ├── IApplicationStorage.cs
│ │ │ │ │ ├── IExpressionUtility.cs
│ │ │ │ │ ├── IPlatform.cs
│ │ │ │ │ ├── IPlatformInformation.cs
│ │ │ │ │ ├── IPushUtility.cs
│ │ │ │ │ ├── Platform.cs
│ │ │ │ │ └── PreserveAttribute.cs
│ │ │ │ ├── Properties/
│ │ │ │ │ └── AssemblyInfo.cs
│ │ │ │ ├── Push/
│ │ │ │ │ ├── ILocalStorageManager.cs
│ │ │ │ │ ├── IRegistrationManager.cs
│ │ │ │ │ ├── LocalStorageManager.cs
│ │ │ │ │ ├── PushHttpClient.cs
│ │ │ │ │ ├── Registration.cs
│ │ │ │ │ ├── RegistrationClassConverter.cs
│ │ │ │ │ ├── RegistrationManager.cs
│ │ │ │ │ └── StoredRegistrationEntry.cs
│ │ │ │ ├── Resources.Designer.cs
│ │ │ │ ├── Resources.resx
│ │ │ │ ├── Table/
│ │ │ │ │ ├── IMobileServiceTable.Generic.cs
│ │ │ │ │ ├── IMobileServiceTable.cs
│ │ │ │ │ ├── MobileServiceObjectReader.cs
│ │ │ │ │ ├── MobileServiceSystemColumns.cs
│ │ │ │ │ ├── MobileServiceSystemProperties.cs
│ │ │ │ │ ├── MobileServiceTable.Generic.cs
│ │ │ │ │ ├── MobileServiceTable.cs
│ │ │ │ │ ├── Query/
│ │ │ │ │ │ ├── IQueryResultEnumerable.cs
│ │ │ │ │ │ ├── ITotalCountProvider.cs
│ │ │ │ │ │ ├── Linq/
│ │ │ │ │ │ │ ├── FilterBuildingExpressionVisitor.cs
│ │ │ │ │ │ │ ├── IMobileServiceTableQuery.cs
│ │ │ │ │ │ │ ├── MemberInfoKey.cs
│ │ │ │ │ │ │ ├── MobileServiceTableQuery.cs
│ │ │ │ │ │ │ ├── MobileServiceTableQueryProvider.cs
│ │ │ │ │ │ │ └── MobileServiceTableQueryTranslator.cs
│ │ │ │ │ │ ├── MobileServiceTableQueryDescription.cs
│ │ │ │ │ │ ├── OData/
│ │ │ │ │ │ │ ├── BinaryOperatorKind.cs
│ │ │ │ │ │ │ ├── BinaryOperatorNode.cs
│ │ │ │ │ │ │ ├── ConstantNode.cs
│ │ │ │ │ │ │ ├── ConvertNode.cs
│ │ │ │ │ │ │ ├── FunctionCallNode.cs
│ │ │ │ │ │ │ ├── MemberAccessNode.cs
│ │ │ │ │ │ │ ├── ODataExpressionLexer.cs
│ │ │ │ │ │ │ ├── ODataExpressionParser.cs
│ │ │ │ │ │ │ ├── ODataExpressionVisitor.cs
│ │ │ │ │ │ │ ├── OrderByDirection.cs
│ │ │ │ │ │ │ ├── OrderByNode.cs
│ │ │ │ │ │ │ ├── QueryNode.cs
│ │ │ │ │ │ │ ├── QueryNodeKind.cs
│ │ │ │ │ │ │ ├── QueryNodeVisitor.cs
│ │ │ │ │ │ │ ├── QueryToken.cs
│ │ │ │ │ │ │ ├── QueryTokenKind.cs
│ │ │ │ │ │ │ ├── UnaryOperatorKind.cs
│ │ │ │ │ │ │ └── UnaryOperatorNode.cs
│ │ │ │ │ │ ├── ODataOptions.cs
│ │ │ │ │ │ ├── QueryResult.cs
│ │ │ │ │ │ ├── QueryResultEnumerable.cs
│ │ │ │ │ │ └── QueryResultList.cs
│ │ │ │ │ ├── Serialization/
│ │ │ │ │ │ ├── CreatedAtAttribute.cs
│ │ │ │ │ │ ├── DataTableAttribute.cs
│ │ │ │ │ │ ├── DeletedAttribute.cs
│ │ │ │ │ │ ├── ISystemPropertyAttribute.cs
│ │ │ │ │ │ ├── MobileServiceContractResolver.cs
│ │ │ │ │ │ ├── MobileServiceIsoDateTimeConverter.cs
│ │ │ │ │ │ ├── MobileServiceJsonSerializerSettings.cs
│ │ │ │ │ │ ├── MobileServicePrecisionCheckConverter.cs
│ │ │ │ │ │ ├── MobileServiceSerializer.cs
│ │ │ │ │ │ ├── UpdatedAtAttribute.cs
│ │ │ │ │ │ └── VersionAttribute.cs
│ │ │ │ │ └── Sync/
│ │ │ │ │ ├── IMobileServiceLocalStore.cs
│ │ │ │ │ ├── IMobileServiceSyncContext.cs
│ │ │ │ │ ├── IMobileServiceSyncHandler.cs
│ │ │ │ │ ├── IMobileServiceSyncTable.Generic.cs
│ │ │ │ │ ├── IMobileServiceSyncTable.cs
│ │ │ │ │ ├── MobileServiceLocalStore.cs
│ │ │ │ │ ├── MobileServiceLocalSystemTables.cs
│ │ │ │ │ ├── MobileServicePushCompletionResult.cs
│ │ │ │ │ ├── MobileServicePushStatus.cs
│ │ │ │ │ ├── MobileServiceRemoteTableOptions.cs
│ │ │ │ │ ├── MobileServiceSyncContext.cs
│ │ │ │ │ ├── MobileServiceSyncHandler.cs
│ │ │ │ │ ├── MobileServiceSyncSettingsManager.cs
│ │ │ │ │ ├── MobileServiceSyncTable.Generic.cs
│ │ │ │ │ ├── MobileServiceSyncTable.cs
│ │ │ │ │ ├── PullOptions.cs
│ │ │ │ │ └── Queue/
│ │ │ │ │ ├── Actions/
│ │ │ │ │ │ ├── IncrementalPullStrategy.cs
│ │ │ │ │ │ ├── PullAction.cs
│ │ │ │ │ │ ├── PullCursor.cs
│ │ │ │ │ │ ├── PullStrategy.cs
│ │ │ │ │ │ ├── PurgeAction.cs
│ │ │ │ │ │ ├── PushAction.cs
│ │ │ │ │ │ ├── SyncAction.cs
│ │ │ │ │ │ └── TableAction.cs
│ │ │ │ │ ├── OperationBatch.cs
│ │ │ │ │ ├── OperationQueue.cs
│ │ │ │ │ └── Operations/
│ │ │ │ │ ├── DeleteOperation.cs
│ │ │ │ │ ├── IMobileServiceTableOperation.cs
│ │ │ │ │ ├── InsertOperation.cs
│ │ │ │ │ ├── MobileServiceTableKind.cs
│ │ │ │ │ ├── MobileServiceTableOperation.cs
│ │ │ │ │ ├── MobileServiceTableOperationError.cs
│ │ │ │ │ ├── MobileServiceTableOperationKind.cs
│ │ │ │ │ ├── MobileServiceTableOperationState.cs
│ │ │ │ │ └── UpdateOperation.cs
│ │ │ │ ├── Threading/
│ │ │ │ │ ├── ActionBlock.cs
│ │ │ │ │ ├── AsyncLock.cs
│ │ │ │ │ ├── AsyncLockDictionary.cs
│ │ │ │ │ ├── AsyncReaderWriterLock.cs
│ │ │ │ │ └── DisposeAction.cs
│ │ │ │ └── packages.config
│ │ │ ├── Microsoft.WindowsAzure.MobileServices.Android/
│ │ │ │ ├── Authentication/
│ │ │ │ │ └── MobileServiceUIAuthentication.cs
│ │ │ │ ├── ExpressionUtility/
│ │ │ │ │ └── ExpressionVisitor.cs
│ │ │ │ ├── Extensions/
│ │ │ │ │ └── MobileServiceClientExtensions.cs
│ │ │ │ ├── Microsoft.WindowsAzure.Mobile.Ext.Android.csproj
│ │ │ │ ├── Platform/
│ │ │ │ │ ├── ApplicationStorage.cs
│ │ │ │ │ ├── CurrentPlatform.cs
│ │ │ │ │ ├── PlatformInformation.cs
│ │ │ │ │ └── PushUtility.cs
│ │ │ │ ├── Properties/
│ │ │ │ │ └── AssemblyInfo.cs
│ │ │ │ ├── Push/
│ │ │ │ │ ├── GcmRegistration.cs
│ │ │ │ │ ├── GcmTemplateRegistration.cs
│ │ │ │ │ └── Push.cs
│ │ │ │ ├── Resources/
│ │ │ │ │ └── Resource.designer.cs
│ │ │ │ ├── app.config
│ │ │ │ └── packages.config
│ │ │ ├── Microsoft.WindowsAzure.MobileServices.Net45/
│ │ │ │ ├── Microsoft.WindowsAzure.Mobile.Ext.Net45.csproj
│ │ │ │ ├── Platform/
│ │ │ │ │ ├── ApplicationStorage.cs
│ │ │ │ │ ├── CurrentPlatform.cs
│ │ │ │ │ └── PlatformInformation.cs
│ │ │ │ ├── Properties/
│ │ │ │ │ └── AssemblyInfo.cs
│ │ │ │ ├── app.config
│ │ │ │ └── packages.config
│ │ │ ├── Microsoft.WindowsAzure.MobileServices.SQLiteStore/
│ │ │ │ ├── ColumnDefinition.cs
│ │ │ │ ├── Extensions/
│ │ │ │ │ └── EnumerableExtensions.cs
│ │ │ │ ├── Microsoft.WindowsAzure.Mobile.SQLiteStore.csproj
│ │ │ │ ├── MobileServiceSQLiteStore.cs
│ │ │ │ ├── MobileServiceSQLiteStoreExtensions.cs
│ │ │ │ ├── Properties/
│ │ │ │ │ ├── AssemblyInfo.cs
│ │ │ │ │ ├── Resources.Designer.cs
│ │ │ │ │ └── Resources.resx
│ │ │ │ ├── SqlColumnType.cs
│ │ │ │ ├── SqlHelpers.cs
│ │ │ │ ├── SqlQueryFormatter.cs
│ │ │ │ ├── TableDefinition.cs
│ │ │ │ └── packages.config
│ │ │ ├── Microsoft.WindowsAzure.MobileServices.WindowsPhone8/
│ │ │ │ ├── Microsoft.WindowsAzure.Mobile.Ext.WP8.csproj
│ │ │ │ ├── Platform/
│ │ │ │ │ ├── ApplicationStorage.cs
│ │ │ │ │ ├── PlatformInformation.cs
│ │ │ │ │ └── PushUtility.cs
│ │ │ │ ├── Properties/
│ │ │ │ │ └── AssemblyInfo.cs
│ │ │ │ ├── Push/
│ │ │ │ │ ├── MpnsRegistration.cs
│ │ │ │ │ ├── MpnsTemplateRegistration.cs
│ │ │ │ │ └── Push.cs
│ │ │ │ ├── app.config
│ │ │ │ └── packages.config
│ │ │ ├── Microsoft.WindowsAzure.MobileServices.WindowsPhone8.UI/
│ │ │ │ ├── Authentication/
│ │ │ │ │ └── AuthenticationBroker.cs
│ │ │ │ ├── LoginPage.xaml
│ │ │ │ ├── LoginPage.xaml.cs
│ │ │ │ ├── Microsoft.WindowsAzure.Mobile.UI.WP8.csproj
│ │ │ │ ├── Properties/
│ │ │ │ │ └── AssemblyInfo.cs
│ │ │ │ ├── app.config
│ │ │ │ └── packages.config
│ │ │ ├── Microsoft.WindowsAzure.MobileServices.WindowsPhone81/
│ │ │ │ ├── Authentication/
│ │ │ │ │ └── AuthenticationBroker.cs
│ │ │ │ ├── Extensions/
│ │ │ │ │ └── MobileServiceClientExtensions.cs
│ │ │ │ ├── Microsoft.WindowsAzure.Mobile.Ext.WP81.csproj
│ │ │ │ ├── Platform/
│ │ │ │ │ ├── ApplicationStorage.cs
│ │ │ │ │ └── PlatformInformation.cs
│ │ │ │ ├── Properties/
│ │ │ │ │ └── AssemblyInfo.cs
│ │ │ │ ├── app.config
│ │ │ │ └── packages.config
│ │ │ ├── Microsoft.WindowsAzure.MobileServices.WindowsStore/
│ │ │ │ ├── App.config
│ │ │ │ ├── Authentication/
│ │ │ │ │ ├── AuthenticationBroker.cs
│ │ │ │ │ ├── MobileServiceSingleSignOnAuthentication.cs
│ │ │ │ │ └── MobileServiceUIAuthentication.cs
│ │ │ │ ├── Collections/
│ │ │ │ │ └── MobileServiceIncrementalLoadingCollection.cs
│ │ │ │ ├── ExpressionUtility/
│ │ │ │ │ ├── PartialEvaluator.cs
│ │ │ │ │ └── VisitorHelper.cs
│ │ │ │ ├── Extensions/
│ │ │ │ │ ├── MobileServiceClientExtensions.cs
│ │ │ │ │ ├── MobileServiceCollectionViewExtensions.cs
│ │ │ │ │ ├── MobileServiceIncrementalLoadingCollectionExtensions.cs
│ │ │ │ │ └── SingleSignOnExtensions.cs
│ │ │ │ ├── Microsoft.WindowsAzure.Mobile.Ext.Win8.csproj
│ │ │ │ ├── MobileServices.priconfig.xml
│ │ │ │ ├── Platform/
│ │ │ │ │ ├── ApplicationStorage.cs
│ │ │ │ │ ├── CurrentPlatform.cs
│ │ │ │ │ ├── ExpressionUtility.cs
│ │ │ │ │ ├── PlatformInformation.cs
│ │ │ │ │ └── PushUtility.cs
│ │ │ │ ├── Properties/
│ │ │ │ │ └── AssemblyInfo.cs
│ │ │ │ ├── Push/
│ │ │ │ │ ├── Push.cs
│ │ │ │ │ ├── WnsRegistration.cs
│ │ │ │ │ └── WnsTemplateRegistration.cs
│ │ │ │ └── packages.config
│ │ │ └── Microsoft.WindowsAzure.MobileServices.iOS/
│ │ │ ├── Authentication/
│ │ │ │ └── MobileServiceUIAuthentication.cs
│ │ │ ├── Extensions/
│ │ │ │ └── MobileServiceClientExtensions.cs
│ │ │ ├── Microsoft.WindowsAzure.Mobile.Ext.iOS-Classic.csproj
│ │ │ ├── Microsoft.WindowsAzure.Mobile.Ext.iOS.csproj
│ │ │ ├── Platform/
│ │ │ │ ├── ApplicationStorage.cs
│ │ │ │ ├── CurrentPlatform.cs
│ │ │ │ ├── PlatformInformation.cs
│ │ │ │ └── PushUtility.cs
│ │ │ ├── Properties/
│ │ │ │ └── AssemblyInfo.cs
│ │ │ ├── Push/
│ │ │ │ ├── ApnsRegistration.cs
│ │ │ │ ├── ApnsTemplateRegistration.cs
│ │ │ │ └── Push.cs
│ │ │ ├── app.config
│ │ │ └── packages.config
│ │ └── test/
│ │ ├── Microsoft.WindowsAzure.Mobile.Net45.Test/
│ │ │ ├── App.config
│ │ │ ├── App.xaml
│ │ │ ├── App.xaml.cs
│ │ │ ├── Common/
│ │ │ │ └── StandardStyles.xaml
│ │ │ ├── ConsoleHelper.cs
│ │ │ ├── Microsoft.WindowsAzure.Mobile.Net45.Test.csproj
│ │ │ ├── Properties/
│ │ │ │ ├── AssemblyInfo.cs
│ │ │ │ ├── Resources.Designer.cs
│ │ │ │ └── Resources.resx
│ │ │ ├── Settings.Designer.cs
│ │ │ ├── Settings.settings
│ │ │ ├── UI/
│ │ │ │ ├── MainPage.xaml
│ │ │ │ ├── MainPage.xaml.cs
│ │ │ │ ├── MainWindow.xaml
│ │ │ │ ├── MainWindow.xaml.cs
│ │ │ │ ├── TestPage.xaml
│ │ │ │ └── TestPage.xaml.cs
│ │ │ └── packages.config
│ │ ├── Microsoft.WindowsAzure.Mobile.Net45.Vb.Test/
│ │ │ ├── Microsoft.WindowsAzure.Mobile.Net45.Vb.Test.vbproj
│ │ │ ├── My Project/
│ │ │ │ ├── Application.Designer.vb
│ │ │ │ ├── Application.myapp
│ │ │ │ └── AssemblyInfo.vb
│ │ │ ├── QueryTests.vb
│ │ │ ├── TestsForOptionCompareBinary.vb
│ │ │ ├── TestsForOptionCompareText.vb
│ │ │ ├── app.config
│ │ │ └── packages.config
│ │ ├── Microsoft.WindowsAzure.MobileServices.Android.Test/
│ │ │ ├── App.cs
│ │ │ ├── GroupDescription.cs
│ │ │ ├── HarnessActivity.cs
│ │ │ ├── LoginActivity.cs
│ │ │ ├── Microsoft.WindowsAzure.Mobile.Android.Test.csproj
│ │ │ ├── Properties/
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ └── AssemblyInfo.cs
│ │ │ ├── Resources/
│ │ │ │ ├── Layout/
│ │ │ │ │ ├── Harness.axml
│ │ │ │ │ ├── ListedGroup.axml
│ │ │ │ │ ├── ListedTest.axml
│ │ │ │ │ ├── Login.axml
│ │ │ │ │ └── Test.axml
│ │ │ │ ├── Resource.Designer.cs
│ │ │ │ └── Values/
│ │ │ │ └── Strings.xml
│ │ │ ├── TestActivity.cs
│ │ │ ├── TestDescription.cs
│ │ │ ├── TestListener.cs
│ │ │ ├── TestPlatform/
│ │ │ │ └── PushTestUtility.cs
│ │ │ ├── app.config
│ │ │ └── packages.config
│ │ ├── Microsoft.WindowsAzure.MobileServices.SQLiteStore.Android.Test/
│ │ │ ├── App.cs
│ │ │ ├── GroupDescription.cs
│ │ │ ├── HarnessActivity.cs
│ │ │ ├── LoginActivity.cs
│ │ │ ├── Microsoft.WindowsAzure.Mobile.SQLiteStore.Android.Test.csproj
│ │ │ ├── Properties/
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ └── AssemblyInfo.cs
│ │ │ ├── Resources/
│ │ │ │ ├── Layout/
│ │ │ │ │ ├── Harness.axml
│ │ │ │ │ ├── ListedGroup.axml
│ │ │ │ │ ├── ListedTest.axml
│ │ │ │ │ ├── Login.axml
│ │ │ │ │ └── Test.axml
│ │ │ │ ├── Resource.Designer.cs
│ │ │ │ └── Values/
│ │ │ │ └── Strings.xml
│ │ │ ├── TestActivity.cs
│ │ │ ├── TestDescription.cs
│ │ │ ├── TestListener.cs
│ │ │ ├── app.config
│ │ │ └── packages.config
│ │ ├── Microsoft.WindowsAzure.MobileServices.SQLiteStore.Net45.Test/
│ │ │ ├── App.config
│ │ │ ├── App.xaml
│ │ │ ├── App.xaml.cs
│ │ │ ├── Common/
│ │ │ │ └── StandardStyles.xaml
│ │ │ ├── Microsoft.WindowsAzure.Mobile.SQLiteStore.Net45.Test.csproj
│ │ │ ├── Properties/
│ │ │ │ ├── AssemblyInfo.cs
│ │ │ │ ├── Resources.Designer.cs
│ │ │ │ └── Resources.resx
│ │ │ ├── Settings.Designer.cs
│ │ │ ├── Settings.settings
│ │ │ ├── UI/
│ │ │ │ ├── MainPage.xaml
│ │ │ │ ├── MainPage.xaml.cs
│ │ │ │ ├── MainWindow.xaml
│ │ │ │ ├── MainWindow.xaml.cs
│ │ │ │ ├── TestPage.xaml
│ │ │ │ └── TestPage.xaml.cs
│ │ │ └── packages.config
│ │ ├── Microsoft.WindowsAzure.MobileServices.SQLiteStore.Test/
│ │ │ ├── Microsoft.WindowsAzure.Mobile.SQLiteStore.Test.csproj
│ │ │ ├── Properties/
│ │ │ │ └── AssemblyInfo.cs
│ │ │ ├── TestUtilities.cs
│ │ │ ├── UnitTests/
│ │ │ │ ├── SQLiteStoreTests.Integration.cs
│ │ │ │ ├── SQLiteStoreTests.Query.cs
│ │ │ │ ├── SQLiteStoreTests.cs
│ │ │ │ └── SyncSettingsManagerTests.Integration.cs
│ │ │ └── packages.config
│ │ ├── Microsoft.WindowsAzure.MobileServices.SQLiteStore.Test.Unit/
│ │ │ ├── Microsoft.WindowsAzure.Mobile.SQLiteStore.Test.Unit.csproj
│ │ │ ├── MobileServiceSQLiteStoreExtensionTests.cs
│ │ │ ├── Properties/
│ │ │ │ └── AssemblyInfo.cs
│ │ │ ├── SqlHelperTests.cs
│ │ │ ├── SqlQueryFormatterTests.cs
│ │ │ ├── app.config
│ │ │ └── packages.config
│ │ ├── Microsoft.WindowsAzure.MobileServices.SQLiteStore.WindowsPhone8.Test/
│ │ │ ├── App.xaml
│ │ │ ├── App.xaml.cs
│ │ │ ├── LocalizedStrings.cs
│ │ │ ├── MainPage.xaml
│ │ │ ├── MainPage.xaml.cs
│ │ │ ├── Microsoft.WindowsAzure.Mobile.SQLiteStore.WP8.Test.csproj
│ │ │ ├── Properties/
│ │ │ │ ├── AppManifest.xml
│ │ │ │ ├── AssemblyInfo.cs
│ │ │ │ └── WMAppManifest.xml
│ │ │ ├── Resources/
│ │ │ │ ├── AppResources.Designer.cs
│ │ │ │ └── AppResources.resx
│ │ │ ├── app.config
│ │ │ └── packages.config
│ │ ├── Microsoft.WindowsAzure.MobileServices.SQLiteStore.WindowsStore.Test/
│ │ │ ├── App.xaml
│ │ │ ├── App.xaml.cs
│ │ │ ├── Common/
│ │ │ │ └── StandardStyles.xaml
│ │ │ ├── Microsoft.WindowsAzure.Mobile.SQLiteStore.Win8.Test.csproj
│ │ │ ├── Microsoft.WindowsAzure.Mobile.SQLiteStore.Win8.Test_TemporaryKey.pfx
│ │ │ ├── Mocks/
│ │ │ │ └── MobileServiceTableQueryMock.cs
│ │ │ ├── Package.appxmanifest
│ │ │ ├── Properties/
│ │ │ │ └── AssemblyInfo.cs
│ │ │ ├── UI/
│ │ │ │ ├── GroupDescription.cs
│ │ │ │ ├── MainPage.xaml
│ │ │ │ ├── MainPage.xaml.cs
│ │ │ │ ├── Microsoft.WindowsAzure.Mobile.Win8.Test_TemporaryKey.pfx
│ │ │ │ ├── TestDescription.cs
│ │ │ │ ├── TestPage.xaml
│ │ │ │ └── TestPage.xaml.cs
│ │ │ └── packages.config
│ │ ├── Microsoft.WindowsAzure.MobileServices.SQLiteStore.iOS.Test/
│ │ │ ├── AppDelegate.cs
│ │ │ ├── Info.plist
│ │ │ ├── Main.cs
│ │ │ ├── Microsoft.WindowsAzure.Mobile.SQLiteStore.iOS.Test.csproj
│ │ │ ├── Properties/
│ │ │ │ └── AssemblyInfo.cs
│ │ │ ├── UI/
│ │ │ │ ├── HarnessViewController.cs
│ │ │ │ ├── LoginViewController.cs
│ │ │ │ └── TestViewController.cs
│ │ │ ├── app.config
│ │ │ ├── packages.config
│ │ │ └── readme.txt
│ │ ├── Microsoft.WindowsAzure.MobileServices.Test/
│ │ │ ├── AssertEx.cs
│ │ │ ├── FunctionalTests/
│ │ │ │ ├── BloggingTest.cs
│ │ │ │ ├── Book.cs
│ │ │ │ ├── DataSourceTest.cs
│ │ │ │ ├── DateTests.cs
│ │ │ │ ├── FunctionalTestBase.cs
│ │ │ │ ├── QueryingTest.cs
│ │ │ │ ├── Table/
│ │ │ │ │ └── MobileServiceTableTest.cs
│ │ │ │ └── ToDoTest.cs
│ │ │ ├── Microsoft.WindowsAzure.Mobile.Test.csproj
│ │ │ ├── Mocks/
│ │ │ │ ├── MobileServiceLocalStoreMock.cs
│ │ │ │ ├── MobileServiceSyncHandlerMock.cs
│ │ │ │ └── MobileServiceTableQueryMock.cs
│ │ │ ├── Properties/
│ │ │ │ └── AssemblyInfo.cs
│ │ │ ├── SerializationTypes/
│ │ │ │ ├── BaseTypes.cs
│ │ │ │ ├── ComplexType.cs
│ │ │ │ ├── ConverterType.cs
│ │ │ │ ├── DataContractDerivedDataContractType.cs
│ │ │ │ ├── DataContractDerivedJsonPropertyType.cs
│ │ │ │ ├── DataContractDerivedPocoType.cs
│ │ │ │ ├── DataContractType.cs
│ │ │ │ ├── DataMemberType.cs
│ │ │ │ ├── DataTableType.cs
│ │ │ │ ├── DerivedDuplicateKeyType.cs
│ │ │ │ ├── DuplicateKeyType.cs
│ │ │ │ ├── IdTypes.cs
│ │ │ │ ├── InterfacePropertyType.cs
│ │ │ │ ├── JObjectTypes.cs
│ │ │ │ ├── JsonContainerType.cs
│ │ │ │ ├── JsonPropertyDerivedDataContractType.cs
│ │ │ │ ├── JsonPropertyDerivedJsonPropertyType.cs
│ │ │ │ ├── JsonPropertyType.cs
│ │ │ │ ├── PocoDerivedDataContractType.cs
│ │ │ │ ├── PocoDerivedJsonPropertyType.cs
│ │ │ │ ├── PocoDerivedPocoType.cs
│ │ │ │ ├── PocoType.cs
│ │ │ │ ├── SerializationTypeUtility.cs
│ │ │ │ ├── SimpleTreeType.cs
│ │ │ │ ├── SystemPropertyTypes.cs
│ │ │ │ ├── TestConverter.cs
│ │ │ │ └── TypeWithConstructor.cs
│ │ │ ├── TestData/
│ │ │ │ ├── IdTestData.cs
│ │ │ │ └── SystemPropertiesTestData.cs
│ │ │ ├── TestPlatform/
│ │ │ │ ├── IPushTestUtility.cs
│ │ │ │ ├── ITestPlatform.cs
│ │ │ │ ├── MissingPushTestUtility.cs
│ │ │ │ ├── MissingTestPlatform.cs
│ │ │ │ └── TestPlatform.cs
│ │ │ ├── UnitTests/
│ │ │ │ ├── Authentication/
│ │ │ │ │ └── MobileServiceTokenAuthenticationTests.cs
│ │ │ │ ├── Collections/
│ │ │ │ │ └── MobileServiceCollection.Test.cs
│ │ │ │ ├── Http/
│ │ │ │ │ └── HttpUtilityTests.cs
│ │ │ │ ├── HttpHandlers/
│ │ │ │ │ ├── ComplexDelegatingHandler.cs
│ │ │ │ │ └── TestHttpHandler.cs
│ │ │ │ ├── MobileServiceClient.Test.cs
│ │ │ │ ├── MobileServiceFeatures.Test.cs
│ │ │ │ ├── MobileServiceUrlBuilder.Test.cs
│ │ │ │ ├── MobileServiceUser.Test.cs
│ │ │ │ ├── OData/
│ │ │ │ │ └── ODataExpressionParser.Test.cs
│ │ │ │ ├── Push/
│ │ │ │ │ ├── LocalStorageMananger.Test.cs
│ │ │ │ │ └── PushHttpClient.Test.cs
│ │ │ │ └── Table/
│ │ │ │ ├── MobileServiceObjectReaderTests.cs
│ │ │ │ ├── MobileServiceTable.Generic.Test.cs
│ │ │ │ ├── MobileServiceTable.Test.cs
│ │ │ │ ├── Query/
│ │ │ │ │ ├── MemberInfoKey.Test.cs
│ │ │ │ │ └── ZumoQuery.Test.cs
│ │ │ │ ├── Serialization/
│ │ │ │ │ ├── MobileServiceContractResolver.Test.cs
│ │ │ │ │ ├── MobileServiceIsoDateTimeConverter.Test.cs
│ │ │ │ │ ├── MobileServicePrecisionCheckConverter.Test.cs
│ │ │ │ │ └── MobileServiceSerializer.Test.cs
│ │ │ │ └── Sync/
│ │ │ │ ├── MobileServiceSyncContext.Test.cs
│ │ │ │ ├── MobileServiceSyncTable.Generic.Test.cs
│ │ │ │ └── MobileServiceSyncTable.Test.cs
│ │ │ └── packages.config
│ │ ├── Microsoft.WindowsAzure.MobileServices.Test.Unit/
│ │ │ ├── Extensions/
│ │ │ │ ├── ExceptionExtensions.Test.cs
│ │ │ │ └── JTokenExtensionsTests.cs
│ │ │ ├── Microsoft.WindowsAzure.Mobile.Test.Unit.csproj
│ │ │ ├── Properties/
│ │ │ │ └── AssemblyInfo.cs
│ │ │ ├── Table/
│ │ │ │ ├── MobileServiceSyncContextTests.cs
│ │ │ │ ├── Query/
│ │ │ │ │ └── MobileServiceTableQueryDescriptionTests.cs
│ │ │ │ └── Sync/
│ │ │ │ ├── MobileServiceSyncTableTests.cs
│ │ │ │ └── Queue/
│ │ │ │ ├── Actions/
│ │ │ │ │ ├── PullActionTests.cs
│ │ │ │ │ └── PushActionTests.cs
│ │ │ │ └── Operations/
│ │ │ │ ├── DeleteOperationTests.cs
│ │ │ │ ├── InsertOperationTests.cs
│ │ │ │ ├── MobileServiceTableOperationErrorTests.cs
│ │ │ │ ├── MobileServiceTableOperationTests.cs
│ │ │ │ └── UpdateOperationTests.cs
│ │ │ ├── Threading/
│ │ │ │ └── AsyncLockDictionaryTests.cs
│ │ │ ├── app.config
│ │ │ └── packages.config
│ │ ├── Microsoft.WindowsAzure.MobileServices.TestFramework/
│ │ │ ├── Framework/
│ │ │ │ ├── ActionContinuation.cs
│ │ │ │ ├── Assert.cs
│ │ │ │ ├── AsyncTestMethodAsyncAction.cs
│ │ │ │ ├── AsyncTestMethodAttribute.cs
│ │ │ │ ├── ExcludeTestAttribute.cs
│ │ │ │ ├── FunctionalTestAttribute.cs
│ │ │ │ ├── FunctionalTestFilter.cs
│ │ │ │ ├── IAsyncExecution.cs
│ │ │ │ ├── IContinuation.cs
│ │ │ │ ├── ITestReporter.cs
│ │ │ │ ├── TagAttribute.cs
│ │ │ │ ├── TagManager.ExpressionEvaluator.cs
│ │ │ │ ├── TagManager.Tags.cs
│ │ │ │ ├── TagManager.cs
│ │ │ │ ├── TagTestFilter.cs
│ │ │ │ ├── TestBase.cs
│ │ │ │ ├── TestFilter.cs
│ │ │ │ ├── TestGroup.cs
│ │ │ │ ├── TestHarness.cs
│ │ │ │ ├── TestMethod.cs
│ │ │ │ ├── TestMethodAsyncAction.cs
│ │ │ │ ├── TestMethodAttribute.cs
│ │ │ │ └── TestSettings.cs
│ │ │ ├── Microsoft.WindowsAzure.Mobile.TestFramework.csproj
│ │ │ ├── Properties/
│ │ │ │ └── AssemblyInfo.cs
│ │ │ └── packages.config
│ │ ├── Microsoft.WindowsAzure.MobileServices.WindowsPhone8.Test/
│ │ │ ├── App.xaml
│ │ │ ├── App.xaml.cs
│ │ │ ├── LocalizedStrings.cs
│ │ │ ├── MainPage.xaml
│ │ │ ├── MainPage.xaml.cs
│ │ │ ├── Microsoft.WindowsAzure.Mobile.WP8.Test.csproj
│ │ │ ├── Package.appxmanifest
│ │ │ ├── PlatformTests/
│ │ │ │ └── LoginTests.cs
│ │ │ ├── Properties/
│ │ │ │ ├── AppManifest.xml
│ │ │ │ ├── AssemblyInfo.cs
│ │ │ │ └── WMAppManifest.xml
│ │ │ ├── Resources/
│ │ │ │ ├── AppResources.Designer.cs
│ │ │ │ └── AppResources.resx
│ │ │ ├── TestPlatform/
│ │ │ │ └── PushTestUtility.cs
│ │ │ ├── UnitTests/
│ │ │ │ └── MobileServiceSerializer.Test.cs
│ │ │ ├── app.config
│ │ │ └── packages.config
│ │ ├── Microsoft.WindowsAzure.MobileServices.WindowsPhone81.Test/
│ │ │ ├── App.xaml
│ │ │ ├── App.xaml.cs
│ │ │ ├── MainPage.xaml
│ │ │ ├── MainPage.xaml.cs
│ │ │ ├── Microsoft.WindowsAzure.Mobile.WP81.Test.csproj
│ │ │ ├── Package.appxmanifest
│ │ │ ├── Properties/
│ │ │ │ └── AssemblyInfo.cs
│ │ │ ├── UI/
│ │ │ │ ├── LoginPage.xaml
│ │ │ │ └── LoginPage.xaml.cs
│ │ │ ├── app.config
│ │ │ └── packages.config
│ │ ├── Microsoft.WindowsAzure.MobileServices.WindowsStore.Test/
│ │ │ ├── App.xaml
│ │ │ ├── App.xaml.cs
│ │ │ ├── Common/
│ │ │ │ └── StandardStyles.xaml
│ │ │ ├── Functional/
│ │ │ │ └── PushFunctional.Test.cs
│ │ │ ├── Microsoft.WindowsAzure.Mobile.Win8.Test.csproj
│ │ │ ├── Microsoft.WindowsAzure.Mobile.Win8.Test_TemporaryKey.pfx
│ │ │ ├── Mocks/
│ │ │ │ └── MobileServiceTableQueryMock.cs
│ │ │ ├── Package.appxmanifest
│ │ │ ├── PlatformTests/
│ │ │ │ └── LoginTests.cs
│ │ │ ├── Properties/
│ │ │ │ └── AssemblyInfo.cs
│ │ │ ├── TestPlatform/
│ │ │ │ ├── CurrentTestPlatform.cs
│ │ │ │ └── PushTestUtility.cs
│ │ │ ├── UI/
│ │ │ │ ├── GroupDescription.cs
│ │ │ │ ├── LoginPage.xaml
│ │ │ │ ├── LoginPage.xaml.cs
│ │ │ │ ├── MainPage.xaml
│ │ │ │ ├── MainPage.xaml.cs
│ │ │ │ ├── TestDescription.cs
│ │ │ │ ├── TestPage.xaml
│ │ │ │ └── TestPage.xaml.cs
│ │ │ ├── UnitTests/
│ │ │ │ ├── Collections/
│ │ │ │ │ └── IncrementalLoadingMobileServiceCollection.Test.cs
│ │ │ │ └── PushUnit.Test.cs
│ │ │ └── packages.config
│ │ └── Microsoft.WindowsAzure.MobileServices.iOS.Test/
│ │ ├── AppDelegate.cs
│ │ ├── Info.plist
│ │ ├── Main.cs
│ │ ├── Microsoft.WindowsAzure.Mobile.iOS.Test.csproj
│ │ ├── Properties/
│ │ │ └── AssemblyInfo.cs
│ │ ├── TestPlatform/
│ │ │ └── PushTestUtility.cs
│ │ ├── UI/
│ │ │ ├── HarnessViewController.cs
│ │ │ ├── LoginViewController.cs
│ │ │ └── TestViewController.cs
│ │ ├── UnitTests/
│ │ │ └── PushPlatformTest.cs
│ │ ├── app.config
│ │ ├── packages.config
│ │ └── readme.txt
│ ├── android/
│ │ ├── .gitattributes
│ │ ├── .gitignore
│ │ ├── android-libraries.gradle
│ │ ├── build.gradle
│ │ ├── gradle/
│ │ │ └── wrapper/
│ │ │ └── gradle-wrapper.properties
│ │ ├── gradle.properties
│ │ ├── gradlew
│ │ ├── gradlew.bat
│ │ ├── settings.gradle
│ │ ├── src/
│ │ │ ├── notifications-handler/
│ │ │ │ ├── .settings/
│ │ │ │ │ └── org.eclipse.jdt.core.prefs
│ │ │ │ ├── build.gradle
│ │ │ │ ├── doc/
│ │ │ │ │ ├── allclasses-frame.html
│ │ │ │ │ ├── allclasses-noframe.html
│ │ │ │ │ ├── com/
│ │ │ │ │ │ └── microsoft/
│ │ │ │ │ │ └── windowsazure/
│ │ │ │ │ │ └── notifications/
│ │ │ │ │ │ ├── BuildConfig.html
│ │ │ │ │ │ ├── NotificationsBroadcastReceiver.html
│ │ │ │ │ │ ├── NotificationsHandler.html
│ │ │ │ │ │ ├── NotificationsManager.html
│ │ │ │ │ │ ├── class-use/
│ │ │ │ │ │ │ ├── BuildConfig.html
│ │ │ │ │ │ │ ├── NotificationsBroadcastReceiver.html
│ │ │ │ │ │ │ ├── NotificationsHandler.html
│ │ │ │ │ │ │ └── NotificationsManager.html
│ │ │ │ │ │ ├── package-frame.html
│ │ │ │ │ │ ├── package-summary.html
│ │ │ │ │ │ ├── package-tree.html
│ │ │ │ │ │ └── package-use.html
│ │ │ │ │ ├── constant-values.html
│ │ │ │ │ ├── help-doc.html
│ │ │ │ │ ├── index-files/
│ │ │ │ │ │ ├── index-1.html
│ │ │ │ │ │ ├── index-2.html
│ │ │ │ │ │ ├── index-3.html
│ │ │ │ │ │ ├── index-4.html
│ │ │ │ │ │ ├── index-5.html
│ │ │ │ │ │ ├── index-6.html
│ │ │ │ │ │ └── index-7.html
│ │ │ │ │ ├── index.html
│ │ │ │ │ ├── overview-tree.html
│ │ │ │ │ ├── package-list
│ │ │ │ │ └── stylesheet.css
│ │ │ │ ├── proguard-rules.pro
│ │ │ │ └── src/
│ │ │ │ └── main/
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ ├── java/
│ │ │ │ │ └── com/
│ │ │ │ │ └── microsoft/
│ │ │ │ │ └── windowsazure/
│ │ │ │ │ └── notifications/
│ │ │ │ │ ├── NotificationsBroadcastReceiver.java
│ │ │ │ │ ├── NotificationsHandler.java
│ │ │ │ │ └── NotificationsManager.java
│ │ │ │ └── res/
│ │ │ │ └── values/
│ │ │ │ └── strings.xml
│ │ │ ├── sdk/
│ │ │ │ ├── .pmd
│ │ │ │ ├── .settings/
│ │ │ │ │ └── org.eclipse.jdt.core.prefs
│ │ │ │ ├── build.gradle
│ │ │ │ ├── doc/
│ │ │ │ │ ├── allclasses-frame.html
│ │ │ │ │ ├── allclasses-noframe.html
│ │ │ │ │ ├── com/
│ │ │ │ │ │ └── microsoft/
│ │ │ │ │ │ └── windowsazure/
│ │ │ │ │ │ └── mobileservices/
│ │ │ │ │ │ ├── ApiJsonOperationCallback.html
│ │ │ │ │ │ ├── ApiOperationCallback.html
│ │ │ │ │ │ ├── BuildConfig.html
│ │ │ │ │ │ ├── MobileServiceApplication.html
│ │ │ │ │ │ ├── MobileServiceClient.html
│ │ │ │ │ │ ├── MobileServiceException.html
│ │ │ │ │ │ ├── MobileServiceFeatures.html
│ │ │ │ │ │ ├── MobileServiceList.html
│ │ │ │ │ │ ├── ServiceFilterResponseCallback.html
│ │ │ │ │ │ ├── UserAuthenticationCallback.html
│ │ │ │ │ │ ├── authentication/
│ │ │ │ │ │ │ ├── LoginManager.html
│ │ │ │ │ │ │ ├── MobileServiceAuthenticationProvider.html
│ │ │ │ │ │ │ ├── MobileServiceUser.html
│ │ │ │ │ │ │ ├── class-use/
│ │ │ │ │ │ │ │ ├── LoginManager.html
│ │ │ │ │ │ │ │ ├── MobileServiceAuthenticationProvider.html
│ │ │ │ │ │ │ │ └── MobileServiceUser.html
│ │ │ │ │ │ │ ├── package-frame.html
│ │ │ │ │ │ │ ├── package-summary.html
│ │ │ │ │ │ │ ├── package-tree.html
│ │ │ │ │ │ │ └── package-use.html
│ │ │ │ │ │ ├── class-use/
│ │ │ │ │ │ │ ├── ApiJsonOperationCallback.html
│ │ │ │ │ │ │ ├── ApiOperationCallback.html
│ │ │ │ │ │ │ ├── BuildConfig.html
│ │ │ │ │ │ │ ├── MobileServiceApplication.html
│ │ │ │ │ │ │ ├── MobileServiceClient.html
│ │ │ │ │ │ │ ├── MobileServiceException.html
│ │ │ │ │ │ │ ├── MobileServiceFeatures.html
│ │ │ │ │ │ │ ├── MobileServiceList.html
│ │ │ │ │ │ │ ├── ServiceFilterResponseCallback.html
│ │ │ │ │ │ │ └── UserAuthenticationCallback.html
│ │ │ │ │ │ ├── http/
│ │ │ │ │ │ │ ├── AndroidHttpClientFactory.html
│ │ │ │ │ │ │ ├── AndroidHttpClientFactoryImpl.html
│ │ │ │ │ │ │ ├── HttpPatch.html
│ │ │ │ │ │ │ ├── MobileServiceConnection.html
│ │ │ │ │ │ │ ├── MobileServiceHttpClient.html
│ │ │ │ │ │ │ ├── NextServiceFilterCallback.html
│ │ │ │ │ │ │ ├── RequestAsyncTask.html
│ │ │ │ │ │ │ ├── ServiceFilter.html
│ │ │ │ │ │ │ ├── ServiceFilterRequest.html
│ │ │ │ │ │ │ ├── ServiceFilterRequestImpl.html
│ │ │ │ │ │ │ ├── ServiceFilterResponse.html
│ │ │ │ │ │ │ ├── ServiceFilterResponseImpl.html
│ │ │ │ │ │ │ ├── class-use/
│ │ │ │ │ │ │ │ ├── AndroidHttpClientFactory.html
│ │ │ │ │ │ │ │ ├── AndroidHttpClientFactoryImpl.html
│ │ │ │ │ │ │ │ ├── HttpPatch.html
│ │ │ │ │ │ │ │ ├── MobileServiceConnection.html
│ │ │ │ │ │ │ │ ├── MobileServiceHttpClient.html
│ │ │ │ │ │ │ │ ├── NextServiceFilterCallback.html
│ │ │ │ │ │ │ │ ├── RequestAsyncTask.html
│ │ │ │ │ │ │ │ ├── ServiceFilter.html
│ │ │ │ │ │ │ │ ├── ServiceFilterRequest.html
│ │ │ │ │ │ │ │ ├── ServiceFilterRequestImpl.html
│ │ │ │ │ │ │ │ ├── ServiceFilterResponse.html
│ │ │ │ │ │ │ │ └── ServiceFilterResponseImpl.html
│ │ │ │ │ │ │ ├── package-frame.html
│ │ │ │ │ │ │ ├── package-summary.html
│ │ │ │ │ │ │ ├── package-tree.html
│ │ │ │ │ │ │ └── package-use.html
│ │ │ │ │ │ ├── notifications/
│ │ │ │ │ │ │ ├── GcmNativeRegistration.html
│ │ │ │ │ │ │ ├── GcmTemplateRegistration.html
│ │ │ │ │ │ │ ├── MobileServicePush.html
│ │ │ │ │ │ │ ├── Registration.html
│ │ │ │ │ │ │ ├── RegistrationCallback.html
│ │ │ │ │ │ │ ├── RegistrationGoneException.html
│ │ │ │ │ │ │ ├── TemplateRegistration.html
│ │ │ │ │ │ │ ├── TemplateRegistrationCallback.html
│ │ │ │ │ │ │ ├── UnregisterCallback.html
│ │ │ │ │ │ │ ├── class-use/
│ │ │ │ │ │ │ │ ├── GcmNativeRegistration.html
│ │ │ │ │ │ │ │ ├── GcmTemplateRegistration.html
│ │ │ │ │ │ │ │ ├── MobileServicePush.html
│ │ │ │ │ │ │ │ ├── Registration.html
│ │ │ │ │ │ │ │ ├── RegistrationCallback.html
│ │ │ │ │ │ │ │ ├── RegistrationGoneException.html
│ │ │ │ │ │ │ │ ├── TemplateRegistration.html
│ │ │ │ │ │ │ │ ├── TemplateRegistrationCallback.html
│ │ │ │ │ │ │ │ └── UnregisterCallback.html
│ │ │ │ │ │ │ ├── package-frame.html
│ │ │ │ │ │ │ ├── package-summary.html
│ │ │ │ │ │ │ ├── package-tree.html
│ │ │ │ │ │ │ └── package-use.html
│ │ │ │ │ │ ├── package-frame.html
│ │ │ │ │ │ ├── package-summary.html
│ │ │ │ │ │ ├── package-tree.html
│ │ │ │ │ │ ├── package-use.html
│ │ │ │ │ │ ├── table/
│ │ │ │ │ │ │ ├── MobileServiceJsonTable.html
│ │ │ │ │ │ │ ├── MobileServicePreconditionFailedException.html
│ │ │ │ │ │ │ ├── MobileServicePreconditionFailedExceptionBase.html
│ │ │ │ │ │ │ ├── MobileServiceSystemProperty.html
│ │ │ │ │ │ │ ├── MobileServiceTable.html
│ │ │ │ │ │ │ ├── MobileServiceTableSystemPropertiesProvider.html
│ │ │ │ │ │ │ ├── TableDeleteCallback.html
│ │ │ │ │ │ │ ├── TableJsonOperationCallback.html
│ │ │ │ │ │ │ ├── TableJsonQueryCallback.html
│ │ │ │ │ │ │ ├── TableOperationCallback.html
│ │ │ │ │ │ │ ├── TableQueryCallback.html
│ │ │ │ │ │ │ ├── class-use/
│ │ │ │ │ │ │ │ ├── MobileServiceJsonTable.html
│ │ │ │ │ │ │ │ ├── MobileServicePreconditionFailedException.html
│ │ │ │ │ │ │ │ ├── MobileServicePreconditionFailedExceptionBase.html
│ │ │ │ │ │ │ │ ├── MobileServiceSystemProperty.html
│ │ │ │ │ │ │ │ ├── MobileServiceTable.html
│ │ │ │ │ │ │ │ ├── MobileServiceTableSystemPropertiesProvider.html
│ │ │ │ │ │ │ │ ├── TableDeleteCallback.html
│ │ │ │ │ │ │ │ ├── TableJsonOperationCallback.html
│ │ │ │ │ │ │ │ ├── TableJsonQueryCallback.html
│ │ │ │ │ │ │ │ ├── TableOperationCallback.html
│ │ │ │ │ │ │ │ └── TableQueryCallback.html
│ │ │ │ │ │ │ ├── package-frame.html
│ │ │ │ │ │ │ ├── package-summary.html
│ │ │ │ │ │ │ ├── package-tree.html
│ │ │ │ │ │ │ ├── package-use.html
│ │ │ │ │ │ │ ├── query/
│ │ │ │ │ │ │ │ ├── ExecutableJsonQuery.html
│ │ │ │ │ │ │ │ ├── ExecutableQuery.html
│ │ │ │ │ │ │ │ ├── Query.html
│ │ │ │ │ │ │ │ ├── QueryException.html
│ │ │ │ │ │ │ │ ├── QueryNodeSQLWriter.html
│ │ │ │ │ │ │ │ ├── QueryODataWriter.html
│ │ │ │ │ │ │ │ ├── QueryOperations.html
│ │ │ │ │ │ │ │ ├── QueryOrder.html
│ │ │ │ │ │ │ │ ├── QuerySQLWriter.html
│ │ │ │ │ │ │ │ ├── UnaryOperatorKind.html
│ │ │ │ │ │ │ │ ├── class-use/
│ │ │ │ │ │ │ │ │ ├── ExecutableJsonQuery.html
│ │ │ │ │ │ │ │ │ ├── ExecutableQuery.html
│ │ │ │ │ │ │ │ │ ├── Query.html
│ │ │ │ │ │ │ │ │ ├── QueryException.html
│ │ │ │ │ │ │ │ │ ├── QueryNodeSQLWriter.html
│ │ │ │ │ │ │ │ │ ├── QueryODataWriter.html
│ │ │ │ │ │ │ │ │ ├── QueryOperations.html
│ │ │ │ │ │ │ │ │ ├── QueryOrder.html
│ │ │ │ │ │ │ │ │ ├── QuerySQLWriter.html
│ │ │ │ │ │ │ │ │ └── UnaryOperatorKind.html
│ │ │ │ │ │ │ │ ├── package-frame.html
│ │ │ │ │ │ │ │ ├── package-summary.html
│ │ │ │ │ │ │ │ ├── package-tree.html
│ │ │ │ │ │ │ │ └── package-use.html
│ │ │ │ │ │ │ ├── serialization/
│ │ │ │ │ │ │ │ ├── DateSerializer.html
│ │ │ │ │ │ │ │ ├── JsonEntityParser.html
│ │ │ │ │ │ │ │ ├── LongSerializer.html
│ │ │ │ │ │ │ │ ├── class-use/
│ │ │ │ │ │ │ │ │ ├── DateSerializer.html
│ │ │ │ │ │ │ │ │ ├── JsonEntityParser.html
│ │ │ │ │ │ │ │ │ └── LongSerializer.html
│ │ │ │ │ │ │ │ ├── package-frame.html
│ │ │ │ │ │ │ │ ├── package-summary.html
│ │ │ │ │ │ │ │ ├── package-tree.html
│ │ │ │ │ │ │ │ └── package-use.html
│ │ │ │ │ │ │ └── sync/
│ │ │ │ │ │ │ ├── MobileServiceJsonSyncTable.html
│ │ │ │ │ │ │ ├── MobileServiceSyncContext.html
│ │ │ │ │ │ │ ├── MobileServiceSyncTable.html
│ │ │ │ │ │ │ ├── class-use/
│ │ │ │ │ │ │ │ ├── MobileServiceJsonSyncTable.html
│ │ │ │ │ │ │ │ ├── MobileServiceSyncContext.html
│ │ │ │ │ │ │ │ └── MobileServiceSyncTable.html
│ │ │ │ │ │ │ ├── localstore/
│ │ │ │ │ │ │ │ ├── ColumnDataType.html
│ │ │ │ │ │ │ │ ├── MobileServiceLocalStore.html
│ │ │ │ │ │ │ │ ├── MobileServiceLocalStoreException.html
│ │ │ │ │ │ │ │ ├── SQLiteLocalStore.html
│ │ │ │ │ │ │ │ ├── class-use/
│ │ │ │ │ │ │ │ │ ├── ColumnDataType.html
│ │ │ │ │ │ │ │ │ ├── MobileServiceLocalStore.html
│ │ │ │ │ │ │ │ │ ├── MobileServiceLocalStoreException.html
│ │ │ │ │ │ │ │ │ └── SQLiteLocalStore.html
│ │ │ │ │ │ │ │ ├── package-frame.html
│ │ │ │ │ │ │ │ ├── package-summary.html
│ │ │ │ │ │ │ │ ├── package-tree.html
│ │ │ │ │ │ │ │ └── package-use.html
│ │ │ │ │ │ │ ├── operations/
│ │ │ │ │ │ │ │ ├── DeleteOperation.html
│ │ │ │ │ │ │ │ ├── InsertOperation.html
│ │ │ │ │ │ │ │ ├── LocalTableOperationProcessor.html
│ │ │ │ │ │ │ │ ├── RemoteTableOperationProcessor.html
│ │ │ │ │ │ │ │ ├── TableOperation.html
│ │ │ │ │ │ │ │ ├── TableOperationCollapser.html
│ │ │ │ │ │ │ │ ├── TableOperationError.html
│ │ │ │ │ │ │ │ ├── TableOperationKind.html
│ │ │ │ │ │ │ │ ├── TableOperationVisitor.html
│ │ │ │ │ │ │ │ ├── UpdateOperation.html
│ │ │ │ │ │ │ │ ├── class-use/
│ │ │ │ │ │ │ │ │ ├── DeleteOperation.html
│ │ │ │ │ │ │ │ │ ├── InsertOperation.html
│ │ │ │ │ │ │ │ │ ├── LocalTableOperationProcessor.html
│ │ │ │ │ │ │ │ │ ├── RemoteTableOperationProcessor.html
│ │ │ │ │ │ │ │ │ ├── TableOperation.html
│ │ │ │ │ │ │ │ │ ├── TableOperationCollapser.html
│ │ │ │ │ │ │ │ │ ├── TableOperationError.html
│ │ │ │ │ │ │ │ │ ├── TableOperationKind.html
│ │ │ │ │ │ │ │ │ ├── TableOperationVisitor.html
│ │ │ │ │ │ │ │ │ └── UpdateOperation.html
│ │ │ │ │ │ │ │ ├── package-frame.html
│ │ │ │ │ │ │ │ ├── package-summary.html
│ │ │ │ │ │ │ │ ├── package-tree.html
│ │ │ │ │ │ │ │ └── package-use.html
│ │ │ │ │ │ │ ├── package-frame.html
│ │ │ │ │ │ │ ├── package-summary.html
│ │ │ │ │ │ │ ├── package-tree.html
│ │ │ │ │ │ │ ├── package-use.html
│ │ │ │ │ │ │ ├── push/
│ │ │ │ │ │ │ │ ├── MobileServicePushCompletionResult.html
│ │ │ │ │ │ │ │ ├── MobileServicePushFailedException.html
│ │ │ │ │ │ │ │ ├── MobileServicePushStatus.html
│ │ │ │ │ │ │ │ ├── class-use/
│ │ │ │ │ │ │ │ │ ├── MobileServicePushCompletionResult.html
│ │ │ │ │ │ │ │ │ ├── MobileServicePushFailedException.html
│ │ │ │ │ │ │ │ │ └── MobileServicePushStatus.html
│ │ │ │ │ │ │ │ ├── package-frame.html
│ │ │ │ │ │ │ │ ├── package-summary.html
│ │ │ │ │ │ │ │ ├── package-tree.html
│ │ │ │ │ │ │ │ └── package-use.html
│ │ │ │ │ │ │ ├── queue/
│ │ │ │ │ │ │ │ ├── OperationErrorList.html
│ │ │ │ │ │ │ │ ├── OperationQueue.Bookmark.html
│ │ │ │ │ │ │ │ ├── OperationQueue.html
│ │ │ │ │ │ │ │ ├── class-use/
│ │ │ │ │ │ │ │ │ ├── OperationErrorList.html
│ │ │ │ │ │ │ │ │ ├── OperationQueue.Bookmark.html
│ │ │ │ │ │ │ │ │ └── OperationQueue.html
│ │ │ │ │ │ │ │ ├── package-frame.html
│ │ │ │ │ │ │ │ ├── package-summary.html
│ │ │ │ │ │ │ │ ├── package-tree.html
│ │ │ │ │ │ │ │ └── package-use.html
│ │ │ │ │ │ │ └── synchandler/
│ │ │ │ │ │ │ ├── MobileServiceSyncHandler.html
│ │ │ │ │ │ │ ├── MobileServiceSyncHandlerException.html
│ │ │ │ │ │ │ ├── SimpleSyncHandler.html
│ │ │ │ │ │ │ ├── class-use/
│ │ │ │ │ │ │ │ ├── MobileServiceSyncHandler.html
│ │ │ │ │ │ │ │ ├── MobileServiceSyncHandlerException.html
│ │ │ │ │ │ │ │ └── SimpleSyncHandler.html
│ │ │ │ │ │ │ ├── package-frame.html
│ │ │ │ │ │ │ ├── package-summary.html
│ │ │ │ │ │ │ ├── package-tree.html
│ │ │ │ │ │ │ └── package-use.html
│ │ │ │ │ │ └── threading/
│ │ │ │ │ │ ├── MultiLockDictionary.MultiLock.html
│ │ │ │ │ │ ├── MultiLockDictionary.html
│ │ │ │ │ │ ├── MultiReadWriteLockDictionary.MultiReadWriteLock.html
│ │ │ │ │ │ ├── MultiReadWriteLockDictionary.html
│ │ │ │ │ │ ├── class-use/
│ │ │ │ │ │ │ ├── MultiLockDictionary.MultiLock.html
│ │ │ │ │ │ │ ├── MultiLockDictionary.html
│ │ │ │ │ │ │ ├── MultiReadWriteLockDictionary.MultiReadWriteLock.html
│ │ │ │ │ │ │ └── MultiReadWriteLockDictionary.html
│ │ │ │ │ │ ├── package-frame.html
│ │ │ │ │ │ ├── package-summary.html
│ │ │ │ │ │ ├── package-tree.html
│ │ │ │ │ │ └── package-use.html
│ │ │ │ │ ├── constant-values.html
│ │ │ │ │ ├── deprecated-list.html
│ │ │ │ │ ├── help-doc.html
│ │ │ │ │ ├── index-files/
│ │ │ │ │ │ ├── index-1.html
│ │ │ │ │ │ ├── index-10.html
│ │ │ │ │ │ ├── index-11.html
│ │ │ │ │ │ ├── index-12.html
│ │ │ │ │ │ ├── index-13.html
│ │ │ │ │ │ ├── index-14.html
│ │ │ │ │ │ ├── index-15.html
│ │ │ │ │ │ ├── index-16.html
│ │ │ │ │ │ ├── index-17.html
│ │ │ │ │ │ ├── index-18.html
│ │ │ │ │ │ ├── index-19.html
│ │ │ │ │ │ ├── index-2.html
│ │ │ │ │ │ ├── index-20.html
│ │ │ │ │ │ ├── index-21.html
│ │ │ │ │ │ ├── index-22.html
│ │ │ │ │ │ ├── index-23.html
│ │ │ │ │ │ ├── index-24.html
│ │ │ │ │ │ ├── index-3.html
│ │ │ │ │ │ ├── index-4.html
│ │ │ │ │ │ ├── index-5.html
│ │ │ │ │ │ ├── index-6.html
│ │ │ │ │ │ ├── index-7.html
│ │ │ │ │ │ ├── index-8.html
│ │ │ │ │ │ └── index-9.html
│ │ │ │ │ ├── index.html
│ │ │ │ │ ├── overview-frame.html
│ │ │ │ │ ├── overview-summary.html
│ │ │ │ │ ├── overview-tree.html
│ │ │ │ │ ├── package-list
│ │ │ │ │ ├── script.js
│ │ │ │ │ ├── serialized-form.html
│ │ │ │ │ └── stylesheet.css
│ │ │ │ ├── proguard-rules.pro
│ │ │ │ └── src/
│ │ │ │ └── main/
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ ├── java/
│ │ │ │ │ └── com/
│ │ │ │ │ └── microsoft/
│ │ │ │ │ └── windowsazure/
│ │ │ │ │ └── mobileservices/
│ │ │ │ │ ├── ApiJsonOperationCallback.java
│ │ │ │ │ ├── ApiOperationCallback.java
│ │ │ │ │ ├── MobileServiceApplication.java
│ │ │ │ │ ├── MobileServiceClient.java
│ │ │ │ │ ├── MobileServiceException.java
│ │ │ │ │ ├── MobileServiceFeatures.java
│ │ │ │ │ ├── MobileServiceList.java
│ │ │ │ │ ├── ServiceFilterResponseCallback.java
│ │ │ │ │ ├── UserAuthenticationCallback.java
│ │ │ │ │ ├── authentication/
│ │ │ │ │ │ ├── LoginManager.java
│ │ │ │ │ │ ├── MobileServiceAuthenticationProvider.java
│ │ │ │ │ │ └── MobileServiceUser.java
│ │ │ │ │ ├── http/
│ │ │ │ │ │ ├── AndroidHttpClientFactory.java
│ │ │ │ │ │ ├── AndroidHttpClientFactoryImpl.java
│ │ │ │ │ │ ├── HttpPatch.java
│ │ │ │ │ │ ├── MobileServiceConnection.java
│ │ │ │ │ │ ├── MobileServiceHttpClient.java
│ │ │ │ │ │ ├── NextServiceFilterCallback.java
│ │ │ │ │ │ ├── RequestAsyncTask.java
│ │ │ │ │ │ ├── ServiceFilter.java
│ │ │ │ │ │ ├── ServiceFilterRequest.java
│ │ │ │ │ │ ├── ServiceFilterRequestImpl.java
│ │ │ │ │ │ ├── ServiceFilterResponse.java
│ │ │ │ │ │ └── ServiceFilterResponseImpl.java
│ │ │ │ │ ├── notifications/
│ │ │ │ │ │ ├── GcmNativeRegistration.java
│ │ │ │ │ │ ├── GcmTemplateRegistration.java
│ │ │ │ │ │ ├── MobileServicePush.java
│ │ │ │ │ │ ├── PnsSpecificRegistrationFactory.java
│ │ │ │ │ │ ├── Registration.java
│ │ │ │ │ │ ├── RegistrationCallback.java
│ │ │ │ │ │ ├── RegistrationGoneException.java
│ │ │ │ │ │ ├── TemplateRegistration.java
│ │ │ │ │ │ ├── TemplateRegistrationCallback.java
│ │ │ │ │ │ └── UnregisterCallback.java
│ │ │ │ │ ├── table/
│ │ │ │ │ │ ├── DateTimeOffset.java
│ │ │ │ │ │ ├── MobileServiceConflictException.java
│ │ │ │ │ │ ├── MobileServiceConflictExceptionJson.java
│ │ │ │ │ │ ├── MobileServiceExceptionBase.java
│ │ │ │ │ │ ├── MobileServiceJsonTable.java
│ │ │ │ │ │ ├── MobileServicePreconditionFailedException.java
│ │ │ │ │ │ ├── MobileServicePreconditionFailedExceptionJson.java
│ │ │ │ │ │ ├── MobileServiceSystemColumns.java
│ │ │ │ │ │ ├── MobileServiceSystemProperty.java
│ │ │ │ │ │ ├── MobileServiceTable.java
│ │ │ │ │ │ ├── MobileServiceTableBase.java
│ │ │ │ │ │ ├── MobileServiceTableSystemPropertiesProvider.java
│ │ │ │ │ │ ├── TableDeleteCallback.java
│ │ │ │ │ │ ├── TableJsonOperationCallback.java
│ │ │ │ │ │ ├── TableJsonQueryCallback.java
│ │ │ │ │ │ ├── TableOperationCallback.java
│ │ │ │ │ │ ├── TableQueryCallback.java
│ │ │ │ │ │ ├── query/
│ │ │ │ │ │ │ ├── BinaryOperatorKind.java
│ │ │ │ │ │ │ ├── BinaryOperatorNode.java
│ │ │ │ │ │ │ ├── BinaryOperatorNodeMerger.java
│ │ │ │ │ │ │ ├── ConstantNode.java
│ │ │ │ │ │ │ ├── ConstantNodeMerger.java
│ │ │ │ │ │ │ ├── ExecutableJsonQuery.java
│ │ │ │ │ │ │ ├── ExecutableQuery.java
│ │ │ │ │ │ │ ├── FieldNode.java
│ │ │ │ │ │ │ ├── FieldNodeMerger.java
│ │ │ │ │ │ │ ├── FunctionCallKind.java
│ │ │ │ │ │ │ ├── FunctionCallNode.java
│ │ │ │ │ │ │ ├── FunctionCallNodeMerger.java
│ │ │ │ │ │ │ ├── Query.java
│ │ │ │ │ │ │ ├── QueryBase.java
│ │ │ │ │ │ │ ├── QueryException.java
│ │ │ │ │ │ │ ├── QueryNode.java
│ │ │ │ │ │ │ ├── QueryNodeKind.java
│ │ │ │ │ │ │ ├── QueryNodeMerger.java
│ │ │ │ │ │ │ ├── QueryNodeODataWriter.java
│ │ │ │ │ │ │ ├── QueryNodeSQLWriter.java
│ │ │ │ │ │ │ ├── QueryNodeVisitor.java
│ │ │ │ │ │ │ ├── QueryODataWriter.java
│ │ │ │ │ │ │ ├── QueryOperations.java
│ │ │ │ │ │ │ ├── QueryOrder.java
│ │ │ │ │ │ │ ├── QuerySQLWriter.java
│ │ │ │ │ │ │ ├── UnaryOperatorKind.java
│ │ │ │ │ │ │ ├── UnaryOperatorNode.java
│ │ │ │ │ │ │ └── UnaryOperatorNodeMerger.java
│ │ │ │ │ │ ├── serialization/
│ │ │ │ │ │ │ ├── DateSerializer.java
│ │ │ │ │ │ │ ├── JsonEntityParser.java
│ │ │ │ │ │ │ └── LongSerializer.java
│ │ │ │ │ │ └── sync/
│ │ │ │ │ │ ├── MobileServiceJsonSyncTable.java
│ │ │ │ │ │ ├── MobileServiceSyncContext.java
│ │ │ │ │ │ ├── MobileServiceSyncTable.java
│ │ │ │ │ │ ├── localstore/
│ │ │ │ │ │ │ ├── ColumnDataInfo.java
│ │ │ │ │ │ │ ├── ColumnDataType.java
│ │ │ │ │ │ │ ├── MobileServiceLocalStore.java
│ │ │ │ │ │ │ ├── MobileServiceLocalStoreException.java
│ │ │ │ │ │ │ └── SQLiteLocalStore.java
│ │ │ │ │ │ ├── operations/
│ │ │ │ │ │ │ ├── DeleteOperation.java
│ │ │ │ │ │ │ ├── DeleteOperationCollapser.java
│ │ │ │ │ │ │ ├── InsertOperation.java
│ │ │ │ │ │ │ ├── InsertOperationCollapser.java
│ │ │ │ │ │ │ ├── LocalTableOperationProcessor.java
│ │ │ │ │ │ │ ├── MobileServiceTableOperationState.java
│ │ │ │ │ │ │ ├── RemoteTableOperationProcessor.java
│ │ │ │ │ │ │ ├── TableOperation.java
│ │ │ │ │ │ │ ├── TableOperationCollapser.java
│ │ │ │ │ │ │ ├── TableOperationError.java
│ │ │ │ │ │ │ ├── TableOperationKind.java
│ │ │ │ │ │ │ ├── TableOperationVisitor.java
│ │ │ │ │ │ │ ├── UpdateOperation.java
│ │ │ │ │ │ │ └── UpdateOperationCollapser.java
│ │ │ │ │ │ ├── pull/
│ │ │ │ │ │ │ ├── IncrementalPullStrategy.java
│ │ │ │ │ │ │ └── PullStrategy.java
│ │ │ │ │ │ ├── push/
│ │ │ │ │ │ │ ├── MobileServicePushCompletionResult.java
│ │ │ │ │ │ │ ├── MobileServicePushFailedException.java
│ │ │ │ │ │ │ └── MobileServicePushStatus.java
│ │ │ │ │ │ ├── queue/
│ │ │ │ │ │ │ ├── OperationErrorList.java
│ │ │ │ │ │ │ └── OperationQueue.java
│ │ │ │ │ │ └── synchandler/
│ │ │ │ │ │ ├── MobileServiceSyncHandler.java
│ │ │ │ │ │ ├── MobileServiceSyncHandlerException.java
│ │ │ │ │ │ └── SimpleSyncHandler.java
│ │ │ │ │ └── threading/
│ │ │ │ │ ├── MultiLockDictionary.java
│ │ │ │ │ └── MultiReadWriteLockDictionary.java
│ │ │ │ └── res/
│ │ │ │ └── values/
│ │ │ │ └── strings.xml
│ │ │ └── tools/
│ │ │ ├── License.rtf
│ │ │ ├── package.bat
│ │ │ └── thirdpartynotices.rtf
│ │ └── test/
│ │ └── sdk.testapp/
│ │ ├── .gitignore
│ │ ├── build.gradle
│ │ ├── proguard-rules.pro
│ │ └── src/
│ │ └── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── microsoft/
│ │ │ └── windowsazure/
│ │ │ └── mobileservices/
│ │ │ └── sdk/
│ │ │ └── testapp/
│ │ │ ├── framework/
│ │ │ │ ├── filters/
│ │ │ │ │ ├── EchoFilter.java
│ │ │ │ │ ├── HttpMetaEchoFilter.java
│ │ │ │ │ ├── NullResponseContentFilter.java
│ │ │ │ │ ├── NullResponseFilter.java
│ │ │ │ │ ├── ServiceFilterRequestMock.java
│ │ │ │ │ ├── ServiceFilterResponseMock.java
│ │ │ │ │ └── StatusLineMock.java
│ │ │ │ └── mocks/
│ │ │ │ ├── MobileServiceLocalStoreMock.java
│ │ │ │ └── MobileServiceSyncHandlerMock.java
│ │ │ └── test/
│ │ │ ├── CustomApiClientTests.java
│ │ │ ├── EnhancedPushTests.java
│ │ │ ├── IdPropertyTests.java
│ │ │ ├── LoginTests.java
│ │ │ ├── MobileServiceClientTests.java
│ │ │ ├── MobileServiceFeaturesTests.java
│ │ │ ├── MobileServiceQueryTests.java
│ │ │ ├── MobileServiceSyncTableTests.java
│ │ │ ├── MobileServiceTableTests.java
│ │ │ ├── MobileServiceUserTests.java
│ │ │ ├── SQLiteStoreQueryTests.java
│ │ │ ├── SQLiteStoreTests.java
│ │ │ ├── SerializationTests.java
│ │ │ ├── ServiceFilterTests.java
│ │ │ ├── SystemPropertiesTests.java
│ │ │ ├── URLTests.java
│ │ │ ├── helpers/
│ │ │ │ ├── EncodingUtilities.java
│ │ │ │ └── SQLiteStoreTestsUtilities.java
│ │ │ └── types/
│ │ │ ├── Address.java
│ │ │ ├── ComplexPersonTestObject.java
│ │ │ ├── CustomFunctionOneParameter.java
│ │ │ ├── CustomFunctionTwoParameters.java
│ │ │ ├── DateTestObject.java
│ │ │ ├── IdPropertyTestClasses.java
│ │ │ ├── PersonTestObject.java
│ │ │ ├── PersonTestObjectWithStringId.java
│ │ │ ├── PersonTestObjectWithoutId.java
│ │ │ ├── ResultsContainer.java
│ │ │ ├── SystemPropertyTestClasses.java
│ │ │ └── data/
│ │ │ ├── IdTestData.java
│ │ │ └── SystemPropertiesTestData.java
│ │ └── res/
│ │ └── values/
│ │ └── strings.xml
│ └── iOS/
│ ├── .gitignore
│ ├── License.rtf
│ ├── WindowsAzureMobileServices.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ └── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ ├── AzureMobileServicesFunctionalTests.xcscheme
│ │ ├── WindowsAzureMobileServices.xcscheme
│ │ └── WindowsAzureMobileServicesFramework.xcscheme
│ ├── appledoc/
│ │ └── AppledocSettings.plist
│ ├── build.command
│ ├── doxygen.config
│ ├── src/
│ │ ├── Info.plist
│ │ ├── MSAPIConnection.h
│ │ ├── MSAPIConnection.m
│ │ ├── MSAPIRequest.h
│ │ ├── MSAPIRequest.m
│ │ ├── MSClient.h
│ │ ├── MSClient.m
│ │ ├── MSClientConnection.h
│ │ ├── MSClientConnection.m
│ │ ├── MSClientInternal.h
│ │ ├── MSCoreDataStore.h
│ │ ├── MSCoreDataStore.m
│ │ ├── MSDateOffset.h
│ │ ├── MSDateOffset.m
│ │ ├── MSError.h
│ │ ├── MSError.m
│ │ ├── MSFilter.h
│ │ ├── MSJSONSerializer.h
│ │ ├── MSJSONSerializer.m
│ │ ├── MSLocalStorage.h
│ │ ├── MSLocalStorage.m
│ │ ├── MSLogin.h
│ │ ├── MSLogin.m
│ │ ├── MSLoginController.h
│ │ ├── MSLoginController.m
│ │ ├── MSLoginSerializer.h
│ │ ├── MSLoginSerializer.m
│ │ ├── MSLoginView.h
│ │ ├── MSLoginView.m
│ │ ├── MSNaiveISODateFormatter.h
│ │ ├── MSNaiveISODateFormatter.m
│ │ ├── MSOperationQueue.h
│ │ ├── MSOperationQueue.m
│ │ ├── MSPredicateTranslator.h
│ │ ├── MSPredicateTranslator.m
│ │ ├── MSPullSettings.h
│ │ ├── MSPullSettings.m
│ │ ├── MSPullSettingsInternal.h
│ │ ├── MSPush.h
│ │ ├── MSPush.m
│ │ ├── MSPushHttp.h
│ │ ├── MSPushHttp.m
│ │ ├── MSPushRequest.h
│ │ ├── MSPushRequest.m
│ │ ├── MSQuery.h
│ │ ├── MSQuery.m
│ │ ├── MSQueryInternal.h
│ │ ├── MSQueryResult.h
│ │ ├── MSQueryResult.m
│ │ ├── MSQueuePullOperation.h
│ │ ├── MSQueuePullOperation.m
│ │ ├── MSQueuePullOperationInternal.h
│ │ ├── MSQueuePurgeOperation.h
│ │ ├── MSQueuePurgeOperation.m
│ │ ├── MSQueuePushOperation.h
│ │ ├── MSQueuePushOperation.m
│ │ ├── MSRegistrationManager.h
│ │ ├── MSRegistrationManager.m
│ │ ├── MSSDKFeatures.h
│ │ ├── MSSDKFeatures.m
│ │ ├── MSSerializer.h
│ │ ├── MSSyncContext.h
│ │ ├── MSSyncContext.m
│ │ ├── MSSyncContextInternal.h
│ │ ├── MSSyncContextReadResult.h
│ │ ├── MSSyncContextReadResult.m
│ │ ├── MSSyncTable.h
│ │ ├── MSSyncTable.m
│ │ ├── MSTable.h
│ │ ├── MSTable.m
│ │ ├── MSTableConfigValue.h
│ │ ├── MSTableConfigValue.m
│ │ ├── MSTableConnection.h
│ │ ├── MSTableConnection.m
│ │ ├── MSTableInternal.h
│ │ ├── MSTableOperation.h
│ │ ├── MSTableOperation.m
│ │ ├── MSTableOperationError.h
│ │ ├── MSTableOperationError.m
│ │ ├── MSTableOperationInternal.h
│ │ ├── MSTableRequest.h
│ │ ├── MSTableRequest.m
│ │ ├── MSURLBuilder.h
│ │ ├── MSURLBuilder.m
│ │ ├── MSUser.h
│ │ ├── MSUser.m
│ │ ├── MSUserAgentBuilder.h
│ │ ├── MSUserAgentBuilder.m
│ │ ├── WindowsAzureMobileServices-Prefix.pch
│ │ └── WindowsAzureMobileServices.h
│ └── test/
│ ├── CoreDataTestModel.xcdatamodeld/
│ │ └── CoreDataTestModel.xcdatamodel/
│ │ └── contents
│ ├── MSClientTests.m
│ ├── MSCoreDataStore+TestHelper.h
│ ├── MSCoreDataStore+TestHelper.m
│ ├── MSCoreDataStoreTests.m
│ ├── MSFilterTest.m
│ ├── MSJSONSerializerTests.m
│ ├── MSLocalStorageTests.m
│ ├── MSMultiRequestTestFilter.h
│ ├── MSMultiRequestTestFilter.m
│ ├── MSOfflinePassthroughHelper.h
│ ├── MSOfflinePassthroughHelper.m
│ ├── MSPredicateTranslatorTests.m
│ ├── MSPullSettingsTests.m
│ ├── MSPushHttpTests.m
│ ├── MSPushTests.m
│ ├── MSQueryTests.m
│ ├── MSSyncTableTests.m
│ ├── MSTable+MSTableTestUtilities.h
│ ├── MSTable+MSTableTestUtilities.m
│ ├── MSTableFuncTests.m
│ ├── MSTableOperationErrorTests.m
│ ├── MSTableOperationTests.m
│ ├── MSTableTests.m
│ ├── MSTestFilter.h
│ ├── MSTestFilter.m
│ ├── MSTestWaiter.h
│ ├── MSTestWaiter.m
│ ├── MSURLbuilderTests.m
│ ├── MSUserAgentBuilderTests.m
│ ├── MSUserTests.m
│ ├── TodoItem.h
│ ├── TodoItem.m
│ ├── WindowsAzureMobileServicesFunctionalTests.m
│ ├── WindowsAzureMobileServicesTests-Info.plist
│ ├── en.lproj/
│ │ └── InfoPlist.strings
│ └── settings.plist
└── test/
├── .gitignore
├── Android/
│ ├── Automation/
│ │ └── AndroidAutomation.bat
│ └── ZumoE2ETestApp/
│ ├── .gitignore
│ ├── build.gradle
│ ├── libs/
│ │ ├── getLibs.ps1
│ │ ├── getLibs.sh
│ │ └── required-libs.txt
│ ├── proguard-rules.pro
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── com/
│ │ └── microsoft/
│ │ └── windowsazure/
│ │ └── mobileservices/
│ │ └── zumoe2etestapp/
│ │ ├── Constants.java
│ │ ├── GCMIntentService.java
│ │ ├── MainActivity.java
│ │ ├── TestCaseAdapter.java
│ │ ├── ZumoPreferenceActivity.java
│ │ ├── framework/
│ │ │ ├── CompositeTestGroup.java
│ │ │ ├── ExpectedValueException.java
│ │ │ ├── FroyoAndroidHttpClientFactory.java
│ │ │ ├── FroyoSupport.java
│ │ │ ├── LogServiceFilter.java
│ │ │ ├── TestCase.java
│ │ │ ├── TestExecutionCallback.java
│ │ │ ├── TestGroup.java
│ │ │ ├── TestResult.java
│ │ │ ├── TestStatus.java
│ │ │ ├── Util.java
│ │ │ └── log/
│ │ │ └── DaylightLogger.java
│ │ ├── push/
│ │ │ ├── GCMMessageCallback.java
│ │ │ ├── GCMMessageHelper.java
│ │ │ ├── GCMMessageManager.java
│ │ │ └── GCMRegistrationMessage.java
│ │ └── tests/
│ │ ├── ClientSDKLoginTests.java
│ │ ├── CustomApiTests.java
│ │ ├── EnhancedPushTests.java
│ │ ├── LoginTests.java
│ │ ├── MiscTests.java
│ │ ├── MockResponse.java
│ │ ├── MultipleRequestFilter.java
│ │ ├── OfflineTests.java
│ │ ├── PushTests.java
│ │ ├── QueryTestData.java
│ │ ├── QueryTests.java
│ │ ├── RemoveAuthenticationServiceFilter.java
│ │ ├── RoundTripTests.java
│ │ ├── StringIdTests.java
│ │ ├── SystemPropertiesTests.java
│ │ ├── UpdateDeleteTests.java
│ │ └── types/
│ │ ├── AggregateException.java
│ │ ├── AllIntIdMovies.java
│ │ ├── AllStringIdMovies.java
│ │ ├── ComplexType.java
│ │ ├── ComplexType2.java
│ │ ├── EnumType.java
│ │ ├── FilterResult.java
│ │ ├── IntIdMovie.java
│ │ ├── IntIdRoundTripTableElement.java
│ │ ├── ListFilter.java
│ │ ├── Movie.java
│ │ ├── MovieComparator.java
│ │ ├── ParamsTestTableItem.java
│ │ ├── RoundTripTableElement.java
│ │ ├── SimpleFilter.java
│ │ ├── SimpleMovieFilter.java
│ │ ├── StringIdJsonElement.java
│ │ ├── StringIdMovie.java
│ │ ├── StringIdRoundTripTableElement.java
│ │ ├── StringIdRoundTripTableSoftDeleteElement.java
│ │ ├── StringIdTableItem.java
│ │ └── SystemPropertiesTestData.java
│ └── res/
│ ├── layout/
│ │ ├── activity_main.xml
│ │ └── row_list_test_case.xml
│ ├── menu/
│ │ └── activity_main.xml
│ ├── raw/
│ │ └── mobileservicestore.bks
│ ├── values/
│ │ ├── strings.xml
│ │ ├── strings_activity_zumo_preference.xml
│ │ └── styles.xml
│ ├── values-v11/
│ │ └── styles.xml
│ ├── values-v14/
│ │ └── styles.xml
│ └── xml/
│ └── pref_general.xml
├── JavaScript/
│ ├── .gitignore
│ ├── TestFramework/
│ │ ├── css/
│ │ │ └── default.css
│ │ └── js/
│ │ ├── testFramework.js
│ │ ├── testFrameworkConnections.js
│ │ └── tests/
│ │ ├── allTests.js
│ │ ├── apiTests.js
│ │ ├── loginTests.js
│ │ ├── miscTests.js
│ │ ├── pushTests.js
│ │ ├── queryTestData.js
│ │ ├── queryTests.js
│ │ ├── roundTripTests.js
│ │ └── updateDeleteTests.js
│ └── ZumoE2ETestAppJs/
│ ├── .gitignore
│ ├── ZumoE2ETestAppHTML/
│ │ ├── .gitignore
│ │ ├── Properties/
│ │ │ └── AssemblyInfo.cs
│ │ ├── Web.Debug.config
│ │ ├── Web.Release.config
│ │ ├── Web.config
│ │ ├── ZumoE2ETestAppHTML.csproj
│ │ ├── default.html
│ │ └── js/
│ │ ├── lib/
│ │ │ └── MobileServices.Web.js
│ │ └── platformSpecificFunctions.js
│ ├── ZumoE2ETestAppJs/
│ │ ├── Package.StoreAssociation.xml
│ │ ├── ZumoE2ETestAppJs.jsproj
│ │ ├── ZumoE2ETestAppJs_StoreKey.pfx
│ │ ├── ZumoE2ETestAppJs_TemporaryKey.pfx
│ │ ├── css/
│ │ │ └── where.txt
│ │ ├── default.html
│ │ ├── js/
│ │ │ ├── MobileServices.intellisense.js
│ │ │ ├── MobileServices.js
│ │ │ ├── MobileServices.pri
│ │ │ ├── default.js
│ │ │ ├── platformSpecificFunctions.js
│ │ │ ├── tests/
│ │ │ │ └── where.txt
│ │ │ └── wl.js
│ │ ├── package.appxmanifest
│ │ └── packages.config
│ └── ZumoE2ETestAppJs.sln
├── PLib/
│ ├── .gitignore
│ └── ZumoE2ETestApp/
│ ├── .gitignore
│ ├── .nuget/
│ │ ├── NuGet.Config
│ │ └── NuGet.targets
│ ├── UpgradeLog.htm
│ ├── ZumoE2ETestApp/
│ │ ├── App.xaml
│ │ ├── App.xaml.cs
│ │ ├── Common/
│ │ │ └── StandardStyles.xaml
│ │ ├── Framework/
│ │ │ ├── TestStatus.cs
│ │ │ ├── Util.cs
│ │ │ ├── ZumoPushGlobals.cs
│ │ │ ├── ZumoTest.cs
│ │ │ ├── ZumoTestEventArgs.cs
│ │ │ ├── ZumoTestGlobals.cs
│ │ │ ├── ZumoTestGroup.cs
│ │ │ └── ZumoTestGroupEventArgs.cs
│ │ ├── MainPage.xaml
│ │ ├── MainPage.xaml.cs
│ │ ├── Package.StoreAssociation.xml
│ │ ├── Package.appxmanifest
│ │ ├── Properties/
│ │ │ └── AssemblyInfo.cs
│ │ ├── Tests/
│ │ │ ├── ExceptionTypeWhichWillNeverBeThrown.cs
│ │ │ ├── TestStore.cs
│ │ │ ├── Types/
│ │ │ │ ├── ICloneableItem.cs
│ │ │ │ ├── Movie.cs
│ │ │ │ ├── OfflineReadyItem.cs
│ │ │ │ ├── OfflineReadyItemNoVersion.cs
│ │ │ │ ├── RoundTripTableItem.cs
│ │ │ │ ├── StringIdRoundTripTableItem.cs
│ │ │ │ └── VersionedType.cs
│ │ │ ├── ZumoCUDTests.cs
│ │ │ ├── ZumoCustomApiTests.cs
│ │ │ ├── ZumoLoginTests.cs
│ │ │ ├── ZumoMiscTests.cs
│ │ │ ├── ZumoOfflineTests.cs
│ │ │ ├── ZumoPushTests.cs
│ │ │ ├── ZumoQueryTestData.cs
│ │ │ ├── ZumoQueryTests.cs
│ │ │ ├── ZumoRoundTripTests.cs
│ │ │ ├── ZumoSetupTests.cs
│ │ │ └── ZumoTestCommon.cs
│ │ ├── UIElements/
│ │ │ ├── AppInfoRepository.cs
│ │ │ ├── InputDialog.xaml
│ │ │ ├── InputDialog.xaml.cs
│ │ │ ├── ListViewForTest.cs
│ │ │ ├── ListViewForTestGroup.cs
│ │ │ ├── MoviesDisplayControl.xaml
│ │ │ ├── MoviesDisplayControl.xaml.cs
│ │ │ ├── SaveAppsControl.xaml
│ │ │ ├── SaveAppsControl.xaml.cs
│ │ │ ├── UploadLogsControl.xaml
│ │ │ └── UploadLogsControl.xaml.cs
│ │ ├── ZumoE2ETestApp.csproj
│ │ ├── ZumoE2ETestApp_StoreKey.pfx
│ │ ├── ZumoE2ETestApp_TemporaryKey.pfx
│ │ └── packages.config
│ ├── ZumoE2ETestApp.sln
│ ├── ZumoE2ETestAppNet45/
│ │ ├── App.config
│ │ ├── App.xaml
│ │ ├── App.xaml.cs
│ │ ├── Common/
│ │ │ └── StandardStyles.xaml
│ │ ├── MainPage.xaml
│ │ ├── MainPage.xaml.cs
│ │ ├── MainWindow.xaml
│ │ ├── MainWindow.xaml.cs
│ │ ├── Properties/
│ │ │ ├── AssemblyInfo.cs
│ │ │ ├── Resources.Designer.cs
│ │ │ ├── Resources.resx
│ │ │ ├── Settings.Designer.cs
│ │ │ └── Settings.settings
│ │ ├── UIElements/
│ │ │ ├── InputDialog.xaml
│ │ │ ├── InputDialog.xaml.cs
│ │ │ ├── MoviesDisplayControl.xaml
│ │ │ ├── MoviesDisplayControl.xaml.cs
│ │ │ ├── SaveAppsControl.xaml
│ │ │ ├── SaveAppsControl.xaml.cs
│ │ │ ├── UploadLogsControl.xaml
│ │ │ └── UploadLogsControl.xaml.cs
│ │ ├── ZumoE2ETestAppNet45.csproj
│ │ └── packages.config
│ └── ZumoE2ETestAppWP8/
│ ├── App.xaml
│ ├── App.xaml.cs
│ ├── Framework/
│ │ └── Readme.txt
│ ├── LocalizedStrings.cs
│ ├── MainPage.xaml
│ ├── MainPage.xaml.cs
│ ├── Properties/
│ │ ├── AppManifest.xml
│ │ ├── AssemblyInfo.cs
│ │ └── WMAppManifest.xml
│ ├── Resources/
│ │ ├── AppResources.Designer.cs
│ │ └── AppResources.resx
│ ├── Tests/
│ │ ├── Types/
│ │ │ └── Readme.txt
│ │ └── ZumoWP8PushTests.cs
│ ├── UIElements/
│ │ ├── InputDialog.xaml
│ │ └── InputDialog.xaml.cs
│ ├── ZumoE2ETestAppWP8.csproj
│ ├── app.config
│ └── packages.config
├── SetupScripts/
│ ├── apis/
│ │ ├── SetupAPIs.bat
│ │ ├── SetupAPIs.sh
│ │ ├── admin.js
│ │ ├── admin.json
│ │ ├── application.js
│ │ ├── application.json
│ │ ├── movieFinder.js
│ │ ├── movieFinder.json
│ │ ├── public.js
│ │ ├── public.json
│ │ ├── runtimeInfo.js
│ │ ├── runtimeInfo.json
│ │ ├── shared.js
│ │ ├── shared.json
│ │ ├── user.js
│ │ └── user.json
│ └── tables/
│ ├── ParamsTestTable.delete.js
│ ├── ParamsTestTable.insert.js
│ ├── ParamsTestTable.read.js
│ ├── ParamsTestTable.update.js
│ ├── SetupTables.bat
│ ├── SetupTables.sh
│ ├── authenticated.delete.js
│ ├── authenticated.insert.js
│ ├── authenticated.read.js
│ ├── authenticated.update.js
│ ├── blog_comments.insert.js
│ ├── blog_comments.read.js
│ ├── bothIdTypeMovies.insert.js
│ ├── droidPushTest.insert.js
│ ├── droidRoundTripTable.insert.js
│ ├── droidRoundTripTable.read.js
│ ├── droidRoundTripTable.update.js
│ ├── iosPushTest.insert.js
│ ├── iosRoundTripTable.insert.js
│ ├── offlinereadyitemnoversion.insert.js
│ ├── stringIdRoundTripTable.insert.js
│ ├── stringIdRoundTripTable.read.js
│ ├── stringIdRoundTripTable.update.js
│ ├── w8PushTest.insert.js
│ ├── w8RoundTripTable.insert.js
│ ├── w8RoundTripTable.read.js
│ ├── w8RoundTripTable.update.js
│ ├── w8jsRoundTripTable.insert.js
│ ├── w8jsRoundTripTable.read.js
│ ├── w8jsRoundTripTable.update.js
│ ├── w8jsServerQueryMovies.read.js
│ └── wp8PushTest.insert.js
├── ZumoE2EServerApp/
│ ├── App_Start/
│ │ └── WebApiConfig.cs
│ ├── Controllers/
│ │ ├── AdminController.cs
│ │ ├── ApplicationApiController.cs
│ │ ├── ApplicationController.cs
│ │ ├── AuthenticatedController.cs
│ │ ├── MovieFinderApiController.cs
│ │ ├── OfflineReadyController.cs
│ │ ├── ParamsTestTableController.cs
│ │ ├── PublicController.cs
│ │ ├── RuntimeInfoController.cs
│ │ ├── StringIdMoviesController.cs
│ │ ├── StringIdRoundTripTableController.cs
│ │ ├── W8JSRoundTripTableController.cs
│ │ ├── W8PushTestController.cs
│ │ └── W8RoundTripTableController.cs
│ ├── DataObjects/
│ │ ├── Movie.cs
│ │ ├── OfflineReady.cs
│ │ ├── ParamsTestTableEntity.cs
│ │ ├── RoundTripTableItem.cs
│ │ ├── StringIdRoundTripTableItem.cs
│ │ ├── TestUser.cs
│ │ ├── W8JSRoundTripTableItem.cs
│ │ └── W8PushTestEntity.cs
│ ├── Global.asax
│ ├── Global.asax.cs
│ ├── Models/
│ │ └── SDKClientTestContext.cs
│ ├── Performance/
│ │ └── Microsoft.ServiceBus.MessagingPerformanceCounters.man
│ ├── Properties/
│ │ └── AssemblyInfo.cs
│ ├── ScheduledJobs/
│ │ └── SimpleJob.cs
│ ├── Utils/
│ │ ├── ComplexTypeDomainManager.cs
│ │ ├── CustomSharedApi.cs
│ │ ├── InMemoryDomainManager.cs
│ │ ├── StringIdRoundTripDomainManager.cs
│ │ ├── W8JSRoundTripDomainManager.cs
│ │ └── W8RoundTripDomainManager.cs
│ ├── Web.Debug.config
│ ├── Web.Release.config
│ ├── Web.config
│ ├── ZumoE2EServerApp.csproj
│ ├── ZumoE2EServerApp.sln
│ └── packages.config
└── iOS/
├── .gitignore
└── ZumoE2ETestApp/
├── WindowsAzureMobileServices.framework/
│ ├── Headers/
│ │ ├── MSClient.h
│ │ ├── MSError.h
│ │ ├── MSFilter.h
│ │ ├── MSLoginController.h
│ │ ├── MSPush.h
│ │ ├── MSQuery.h
│ │ ├── MSTable.h
│ │ ├── MSUser.h
│ │ └── WindowsAzureMobileServices.h
│ ├── Versions/
│ │ ├── A/
│ │ │ ├── Headers/
│ │ │ │ ├── MSClient.h
│ │ │ │ ├── MSError.h
│ │ │ │ ├── MSFilter.h
│ │ │ │ ├── MSLoginController.h
│ │ │ │ ├── MSPush.h
│ │ │ │ ├── MSQuery.h
│ │ │ │ ├── MSTable.h
│ │ │ │ ├── MSUser.h
│ │ │ │ └── WindowsAzureMobileServices.h
│ │ │ └── WindowsAzureMobileServices
│ │ └── Current/
│ │ └── Headers/
│ │ ├── MSClient.h
│ │ ├── MSError.h
│ │ ├── MSFilter.h
│ │ ├── MSLoginController.h
│ │ ├── MSPush.h
│ │ ├── MSQuery.h
│ │ ├── MSTable.h
│ │ ├── MSUser.h
│ │ └── WindowsAzureMobileServices.h
│ ├── WindowsAzureMobileServices
│ └── license.rtf
├── ZumoE2ETestApp/
│ ├── TestLoggingFilter.h
│ ├── TestLoggingFilter.m
│ ├── ZumoAppDelegate.h
│ ├── ZumoAppDelegate.m
│ ├── ZumoCUDTests.h
│ ├── ZumoCUDTests.m
│ ├── ZumoCustomApiTests.h
│ ├── ZumoCustomApiTests.m
│ ├── ZumoE2ETestApp-Info.plist
│ ├── ZumoE2ETestApp-Prefix.pch
│ ├── ZumoLogUpdater.h
│ ├── ZumoLogUpdater.m
│ ├── ZumoLoginTests.h
│ ├── ZumoLoginTests.m
│ ├── ZumoMainTableHeader.xib
│ ├── ZumoMainTableViewController.h
│ ├── ZumoMainTableViewController.m
│ ├── ZumoMiscTests.h
│ ├── ZumoMiscTests.m
│ ├── ZumoPushTests.h
│ ├── ZumoPushTests.m
│ ├── ZumoQueryTestData.h
│ ├── ZumoQueryTestData.m
│ ├── ZumoQueryTests.h
│ ├── ZumoQueryTests.m
│ ├── ZumoRoundTripTests.h
│ ├── ZumoRoundTripTests.m
│ ├── ZumoSavedAppsHeader.xib
│ ├── ZumoSavedAppsTableViewController.h
│ ├── ZumoSavedAppsTableViewController.m
│ ├── ZumoTest.h
│ ├── ZumoTest.m
│ ├── ZumoTestCallbacks.h
│ ├── ZumoTestGlobals.h
│ ├── ZumoTestGlobals.m
│ ├── ZumoTestGroup.h
│ ├── ZumoTestGroup.m
│ ├── ZumoTestGroupCallbacks.h
│ ├── ZumoTestGroupTableHeader.xib
│ ├── ZumoTestGroupTableViewController.h
│ ├── ZumoTestGroupTableViewController.m
│ ├── ZumoTestHelpViewController.h
│ ├── ZumoTestHelpViewController.m
│ ├── ZumoTestHelpViewController.xib
│ ├── ZumoTestRunSetup.h
│ ├── ZumoTestRunSetup.m
│ ├── ZumoTestStore.h
│ ├── ZumoTestStore.m
│ ├── en.lproj/
│ │ └── InfoPlist.strings
│ └── main.m
└── ZumoE2ETestApp.xcodeproj/
└── project.pbxproj
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
*.sln merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
================================================
FILE: .gitignore
================================================
.DS_Store
bin
gen
target
*.keystore
*.swp
*.orig
*.log
*.userprefs
seed.txt
map.txt
.metadata
sdk/android/src/notifications-handler/libs/google-play-services.jar
sdk/android/src/sdk/libs/gson-2.2.2.jar
sdk/android/src/sdk/libs/guava-16.0.1.jar
sdk/android/test/sdk.testapp.tests/libs/gson-2.2.2.jar
*.mdf
*.ldf
obj
*.csproj.user
test/ZumoE2EServerApp/Properties/PublishProfiles/
sdk/Managed/test/Microsoft.WindowsAzure.MobileServices.SQLiteStore.Net45.Test/sqlite3.dll
StyleCop.Cache
packages
*.suo
*.jar
*.xccheckout
deriveddata
*.iml
================================================
FILE: .gitmodules
================================================
[submodule "sdk/Javascript/src/External/esprima"]
path = sdk/Javascript/src/External/esprima
url = https://github.com/ariya/esprima.git
[submodule "sdk/Javascript/src/External/queryjs"]
path = sdk/Javascript/src/External/queryjs
url = https://github.com/WindowsAzure/queryjs.git
[submodule "sdk/Managed/src/External/Xamarin.Auth"]
path = sdk/Managed/src/External/Xamarin.Auth
url = https://github.com/azure/azure-mobile-services-xamarin-auth.git
================================================
FILE: CHANGELOG.android.md
================================================
# Azure Mobile Services Android SDK Change Log
### Android SDK: Version 2.0.3
- Fix in the incremental sync query building logic [#720](https://github.com/Azure/azure-mobile-services/issues/720) to use correct parentheses and skip logic [c58d4e8](https://github.com/Azure/azure-mobile-services/commit/c58d4e8)
- Fix for the deserialization bug [#718](https://github.com/Azure/azure-mobile-services/issues/718) on OperationErrorList table with datatype mismatch [15e9f9b](https://github.com/Azure/azure-mobile-services/commit/15e9f9b)
### Android SDK: Version 2.0.2
- Support for operation state tracking
- Fix for type incompatibility from datetime to datetimeoffset
- Methods added for CancelAndDiscard and CancelAndUpdate for customized conflict handling
- Fix for the local store database connection issue caused due to race condition in asynchronous operations
- Updated end to end test
- Support for binary data type on queries (for instance to query using the __version column)
- Improvements on the DateSerializer
### Android SDK: Version 2.0.2-Beta2
- Fix for the pull action with SQLite
### Android SDK: Version 2.0.2-Beta
- Mobile Services SDK version indicator with user-agent
- Introduced conflict exception to facilitate handling of 409 conflict
- Fix for the cropped UI for Facebook authentication
- Fix for SQL ordering issue
- Support for Incremental Sync to pull data with flexibility
- Support for Soft Delete
- Improved SQLite insert performance on pull
- Purge no longer pushes, instead it throws an exception as user expects
- Local item deletion exception is handled properly according to server state
- Support for continuation tokens in queries for paging
- InsertAsync throws expected exception on duplicate insert
- Fix for Local store & SQLite missing/mismatch table columns (i.e. “_deleted”)
- Support for Android Studio
- Send custom query string parameters with loginAsync Android
### Android SDK: Version 1.1.5
- Added support for Windows Azure Notification Hub integration
### Android SDK: Version 1.1.3
- Support for optimistic concurrency (version / ETag) validation
- Support for `__createdAt` / `__updatedAt` table columns
- Added support for the Windows Azure Active Directory authentication in the `MobileServiceAuthenticationProvider` enum.
- Also added a mapping from that name to the value used in the service REST API (`/login/aad`)
### Android SDK: Version 1.1.0
- Support for tables with string ids
- Overload for log in which takes the provider as a string, in addition to the one with enums
================================================
FILE: CHANGELOG.ios.md
================================================
# Azure Mobile Services iOS SDK Change Log
## SDK Downloads
- [Latest iOS 2.x SDK](http://aka.ms/gc6fex)
- **requires XCode 7**
- [iOS 1.2.4 SDK](http://aka.ms/kymw2g)
### Version 2.2.2
- Updated build tooling to use XCode 7 and include BitCode [issue #794](https://github.com/Azure/azure-mobile-services/issues/794)
- Note: Framework now requires using XCode 7
- Fixed issue with MSCoreDataStore.h that prevented it from bring used as part of a cocoapod
### Version 2.2.1
- Fixed [issue #768](https://github.com/Azure/azure-mobile-services/issues/768) that was causing a memory leak when using NSURLSession [204f210](https://github.com/Azure/azure-mobile-services/commit/204f210)
- Fix NSNull templateName [9347390](https://github.com/Azure/azure-mobile-services/commit/9347390)
### Version 2.2.0
- Updated offline sync logic to do a case-insensitive comparison on the ID column [328aadf](https://github.com/Azure/azure-mobile-services/commit/328aadf)
- Added support for returning the underlying NSOperation when performing push, pull and purge operations [7c37f60](https://github.com/Azure/azure-mobile-services/commit/7c37f60)
- Added support for configuring the page size of a pull operation [0c31aa3](https://github.com/Azure/azure-mobile-services/commit/0c31aa3)
- Added support for NSUUID in PredicateTranslator [24c5a61](https://github.com/Azure/azure-mobile-services/commit/24c5a61)
- Fixed [issue #699] (https://github.com/Azure/azure-mobile-services/issues/699) that prevented properties with value nil from being sent to server [bf41081](https://github.com/Azure/azure-mobile-services/commit/bf41081)
- Fixed handling of network errors during push operations [1a9fdf4](https://github.com/Azure/azure-mobile-services/commit/1a9fdf4)
- Fixed potential race conditions while performing table operations [15581be](https://github.com/Azure/azure-mobile-services/commit/15581be)
- Fixed incorrect ID validation during insert operations [f5e44d4](https://github.com/Azure/azure-mobile-services/commit/f5e44d4)
### Version 2.1.0
- Fix cancelAndUpdate and cancelAndDiscard actions on the MSTableOperationError class
- Fix issues with sync operations not firing their completion blocks on the correct queue
### Version 2.0.0
- GA of offline sync changes from previous betas
- Now requires iOS 7 or newer to use
### Version 2.0.0 beta2
- **[Breaking]** Changed MSReadQueryBlock to return MSQueryResult instead of items and totalCount. See [this blog post](http://azure.microsoft.com/blog/2014/10/07/mobile-services-beta-ios-sdk-released/) for more information.
- Added support for incremental sync
- Added support for query parameters in pull operations
- Added support for following link headers returned from the .NET backend
- Fixed issue with login controller completing before animation completes
- Added a method for force purge of local data
- Added a helper method to return an NSDictionary from an NSManagedObject
- Fixed issue with the __includeDeleted flag sending the wrong value
### Version 2.0.0 beta1
- Added support for incremental sync
- Added support for query parameters in pull operations
- Fixed issue with login controller completing before animation completes
- Added a method for force purge of local data
- Added a helper method to return an NSDictionary from an NSManagedObject
- Fixed issue with the __includeDeleted flag sending the wrong value
### Version 1.3 alpha1
- Added support for offline and sync
### Version 1.2.4
- Address bug where version property was returned to the caller even when not asked for
- Fixes Swift QS for syntax changes up to Xcode Beta 7
### Version 1.2.3
- Fix issue with const when using both Azure Messaging and Mobile Services frameworks
- Fix issue [#306](https://github.com/Azure/azure-mobile-services/issues/306) with how arrays passed as query string params to table and custom APIs are converted
- Fix issue where system properties (__version, __updatedAt, etc) were returned to the caller when they were not requested
### Version 1.2.2
- Added support for APNS Azure Notification Hub integration
- Support for optimistic concurrency on delete
### iOS SDK
- - Fix issue [#218](https://github.com/WindowsAzure/azure-mobile-services/issues/218) in which some dates coming from the mobile services with the .NET runtime weren't parsed correctly
### Version 1.1.3
- Added a mapping in the authentication provider from WindowsAzureActiveDirectory to the value used in the REST API (`/login/aad`)
### Version 1.1.2
- Supports the arm64 architecture
- Now requires iOS 6 or newer to use
### Version 1.1.1
- Support for optimistic concurrency (version / ETag) validation
- Support for `__createdAt` / `__updatedAt` table columns
- Fix bug with using arrays in invokeAPI
### Version 1.1.0
- Support for tables with string ids
================================================
FILE: CHANGELOG.javascript.md
================================================
# Azure Mobile Services JavaScript SDK Change Log
### JavaScript SDK: Version 1.2.7
- Added support for phonegap/cordova with [plugin repo](https://github.com/Azure/azure-mobile-services-cordova)
### JavaScript SDK: Version 1.2.5
- Added support for sending provider specific query string parameters in login using new loginWithOptions method
- Added support for registering devices with notification hubs for apns and gcm
- Fixed issue with InAppBrowser on iOS devices during auth workflows when using Cordova/PhoneGap
### JavaScript SDK: Version 1.2.4
- Fixed crash when server response did not have a Content-Type header
### JavaScript SDK: Version 1.2.2
- Support for optimistic concurrency on delete
### JavaScript SDK: Version 1.1.5
- Fix issue [#218](https://github.com/WindowsAzure/azure-mobile-services/issues/218) in which some dates coming from the mobile services with the .NET runtime weren't parsed correctly
- [WinJS only] Fix race condition on notification hub integration initialization when storage was corrupted
### JavaScript SDK: Version 1.1.4
- Added support for Windows Azure Notification Hub integration for WinJS.
### JavaScript SDK: Version 1.1.3
- Added a mapping in the authentication provider from WindowsAzureActiveDirectory to the value used in the REST API (`/login/aad`)
### JavaScript SDK: Version 1.1.2
- Support for optimistic concurrency (version / ETag) validation
- Support for `__createdAt` / `__updatedAt` table columns
### JavaScript SDK: Version 1.1.0
- Support for tables with string ids
- Removed client restriction on valid providers for login
- Files are now served from http://ajax.aspnetcdn.com/ajax/mobileservices/MobileServices.Web-[version].min.js (or [version].js for the non minified copy)
### JavaScript SDK: Version 1.0.3:
- Added support for `String.substr` inside functions on `where` clauses
- Fix [#152](https://github.com/WindowsAzure/azure-mobile-services/issues/152) - InvokeApi method crashes on IE9 and IE8
- Fixed issue with login popup not being closed when using IE11
================================================
FILE: CHANGELOG.managed.md
================================================
# Azure Mobile Services Managed SDK Change Log
### Managed SDK: Version 1.3.2
- Added workaround for WinRT issue [#658](https://github.com/WindowsAzure/azure-mobile-services/issues/658) by removing localization in SQLiteStore and in the SDK [6af8b30](https://github.com/Azure/azure-mobile-services/commit/6af8b30) [58c5a44](https://github.com/Azure/azure-mobile-services/commit/58c5a44)
- Added partial fix for issue [#615](https://github.com/WindowsAzure/azure-mobile-services/issues/615), by removing operations from the queue before releasing the operation's lock. [a28ae32](https://github.com/Azure/azure-mobile-services/commit/a28ae32)
### Managed SDK: Version 1.3.1
- Update to latest version of sqlite pcl [ce1aa67](https://github.com/Azure/azure-mobile-services/commit/ce1aa67)
- Fix iOS classic compilation issues [316a57a](https://github.com/Azure/azure-mobile-services/commit/316a57a)
- Update Xamarin unified support for Xamarin.iOS 8.6
[da537b1](https://github.com/Azure/azure-mobile-services/commit/da537b1)
- Xamarin.iOS Unified API Support [d778c60](https://github.com/Azure/azure-mobile-services/commit/d778c60)
- Relax queryId restrictions #521 [offline]
[3e2f645](https://github.com/Azure/azure-mobile-services/commit/3e2f645)
- Work around for resource missing error on windows phone [offline]
### Managed SDK: Version 1.3
- allow underscore and hyphen in queryId [7d192a3](https://github.com/Azure/azure-mobile-services/commit/7d192a3)
- added force option to purge data and pending operations on data [aa51d9f](https://github.com/Azure/azure-mobile-services/commit/aa51d9f)
- delete errors with operation on cancel and collapse [372ba61](https://github.com/Azure/azure-mobile-services/commit/372ba61)
- rename queryKey to queryId [93e59f7](https://github.com/Azure/azure-mobile-services/commit/93e59f7)
- insert should throw if the item already exists [#491](https://github.com/Azure/azure-mobile-services/issues/491) [fc13891](https://github.com/Azure/azure-mobile-services/commit/fc13891)
- **[Breaking]** Removed PullAsync overloads that do not take queryId [88cac8c](https://github.com/Azure/azure-mobile-services/commit/88cac8c)
### Managed SDK: Version 1.3 beta3
- Improved the push failure error message [d49a72e](https://github.com/Azure/azure-mobile-services/commit/d49a72e)
- Implement true upsert [c5b0b38](https://github.com/Azure/azure-mobile-services/commit/c5b0b38)
- Use more fine grained types in sqlite store [de49712](https://github.com/Azure/azure-mobile-services/commit/de49712)
- Speedup store table creation [eb7cc8d](https://github.com/Azure/azure-mobile-services/commit/eb7cc8d)
- Allow query on member name datetime [7d831cd](https://github.com/Azure/azure-mobile-services/commit/7d831cd)
- Make the sync handler optional as there is alternate way for handling sync errors [edc04e5](https://github.com/Azure/azure-mobile-services/commit/edc04e5)
- Drop the unused createdat column in operations table [8a30df4](https://github.com/Azure/azure-mobile-services/commit/8a30df4)
- Remove redundant overloads in interface and move them to extensions [d0a46b6](https://github.com/Azure/azure-mobile-services/commit/d0a46b6)
- Support relative and absolute uri in pull same as table.read [c9d8e39](https://github.com/Azure/azure-mobile-services/commit/c9d8e39)
- Allow relative URI in invokeapi [5b3c6b3](https://github.com/Azure/azure-mobile-services/commit/5b3c6b3)
- Fixed the like implementation in sqlite store [77a0180](https://github.com/Azure/azure-mobile-services/commit/77a0180)
- Purge should forget the deltatoken [18f1803](https://github.com/Azure/azure-mobile-services/commit/18f1803)
- Renamed fromServer to ignoreMissingColumns [8b047eb](https://github.com/Azure/azure-mobile-services/commit/8b047eb)
- **[Breaking]** Removed PullAsync overloads that do not take queryKey [d4ff784](https://github.com/Azure/azure-mobile-services/commit/d4ff784)
- Save tableKind in the errors table [23f2ef0](https://github.com/Azure/azure-mobile-services/commit/23f2ef0)
### Managed SDK: Version 1.3 beta2
- Updated Nuget references
- Request __deleted system property for sync
- Default delta token set to 1970-01-01 for compatibility with Table Storage
- Expose protected methods from the MobileServiceSQLiteStore for intercepting sql
- **[Breaking]** Expose a ReadOnlyCollection instead of IEnumerable from MobileServiceTableOperationError
### Managed SDK: Version 1.3 beta
- Added support for incremental sync for .NET backend
- Added support for byte[] properties in offline
- Fixed issue with timezone roundtripping in incremental sync
- Improved exception handling for 409 conflicts
- Improved error handling for timeout errors during sync
- Follow link headers returned from .NET backend and use skip and top for PullAsync()
- Introduced the SupportedOptions enum on IMobileServiceSyncTable to configure the pull strategy
- **[Breaking]** Do not Push changes on PurgeAsync() instead throw an exception
- **[Breaking]** Renamed ToQueryString method to ToODataString on MobileServiceTableQueryDescription class
### Managed SDK: Version 1.3 alpha2
- Added support for incremental sync (currently, for Mobile Services JavaScript backend only)
- Added client support for soft delete
- Added support for offline pull with query string
### Managed SDK: Version 1.3 alpha2
- Added support for offline and sync
- Added support for soft delete
### Managed SDK: Version 1.2.6
- Fixed an issue on Xamarin.iOS and Xamarin.Android where UI popups occur during failed user authentication flows. These popups are now suppressed so that the developer can handle the error however they want.
### Managed SDK: Version 1.2.5
- Updated to use a modified build of Xamarin.Auth that will not conflict with any user-included version of Xamarin.Auth
### Managed SDK: Version 1.2.4
- Added support for following link headers returned from the .NET backend
- Added a MobileServiceConflictException to detect duplicate inserts
- Added support for datetimeoffsets in queries
- Added support for sending provider specific query string parameters in LoginAsync()
- Fixed an issue causing duplicate registrations in Xamarin.iOS against .NET backends
### Managed SDK: Version 1.2.3
- Added support for Xamarin iOS Azure Notification Hub integration
### Managed SDK: Version 1.2.2
- Support for optimistic concurrency on delete
- Update to Push surface area with minor object model changes. Added Registration base class in PCL and changed name within each extension to match the push notifcation surface. Example: WnsRegistration, WnsTemplateRegistration
- Added support for Xamarin Android Azure Notification Hub integration
### Managed SDK: Version 1.2.1
- Added support for Windows Phone 8.1, requires using Visual Studio 2013 Update 2 RC
### Managed SDK: Version 1.1.5
- Added support for Xamarin (iOS / Android)
- Clean-up id validation on insert operations
### Managed SDK: Version 1.1.4
- Added support for Windows Azure Notification Hub integration.
### Managed SDK: Version 1.1.3
- Added support for the Windows Azure Active Directory authentication in the `MobileServiceAuthenticationProvider` enumeration.
- Also added a mapping from that name to the value used in the service REST API (`/login/aad`)
- Fixed a issue [#213](https://github.com/WindowsAzure/azure-mobile-services/issues/213) in which SDK prevented calls to custom APIs with query string parameters starting with `$`
### Managed SDK: Version 1.1.2
- Fix [#192](https://github.com/WindowsAzure/azure-mobile-services/issues/192) - Serialized query is ambiguous if double literal has no fractional part
- Fixed Nuget support for Windows Phone 8
### Managed SDK: Version 1.1.1
- Fix bug when inserting a derived type
- Dropped support for Windows Phone 7.x clients (WP7.5 can still use the client version 1.1.0)
### Managed SDK: Version 1.1.0
- Support for tables with string ids
- Support for optimistic concurrency (version / ETag) validation
- Support for `__createdAt` / `__updatedAt` table columns
- Overload for log in which takes the provider as a string, in addition to the one with enums
- Fix [#121](https://github.com/WindowsAzure/azure-mobile-services/issues/121) - exceptions in `MobileServiceIncrementalLoadingCollection.LoadMoreItemsAsync` causes the app to crash
### Managed SDK: Version 1.0.3:
- Fixed query issues in Visual Basic expressions
================================================
FILE: CHANGELOG.md
================================================
# Azure Mobile Services Change Log
## [iOS SDK](CHANGELOG.ios.md)
## [Managed SDK](CHANGELOG.managed.md)
## [Android SDK](CHANGELOG.android.md)
## [JavaScript SDK](CHANGELOG.javascript.md)
================================================
FILE: LICENSE.txt
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
================================================
FILE: README.md
================================================
# Microsoft Azure Mobile Services
Azure Mobile Services has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [Mobile Apps in Azure App Service](https://docs.microsoft.com/en-us/azure/app-service-mobile/app-service-mobile-value-prop).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
## Download Source Code
To get the source code of our SDKs and samples via **git** just type:
git clone https://github.com/Azure/azure-mobile-services.git
cd ./azure-mobile-services/
## Reference Documentation
#### Azure App Service Mobile Apps
* [iOS](http://azure.github.io/azure-mobile-services/iOS/v3)
#### Mobile Services
* [iOS](http://azure.github.io/azure-mobile-services/iOS/v2)
* [Android](http://dl.windowsazure.com/androiddocs/)
## Change log
- [iOS SDK](CHANGELOG.ios.md)
- [Managed SDK](CHANGELOG.managed.md)
- [Android SDK](CHANGELOG.android.md)
- [JavaScript SDK](CHANGELOG.javascript.md)
## Managed Windows Client SDK
Our managed portable library for Windows 8, Windows Phone 8, Windows Phone 8.1, and Windows Runtime Universal C# Client SDK makes it incredibly easy to use Mobile Services from your Windows applications. The [Microsoft Azure Mobile Services SDK](http://nuget.org/packages/WindowsAzure.MobileServices/) is available
as a Nuget package or you can download the source using the instructions above. The managed portable library also supports the full .NET 4.5 platform.
### Prerequisites
The SDK requires Visual Studio 2013.
### Building and Referencing the SDK
The managed portable library solution includes a core portable assembly and platform-specific assemblies for each of the supported platforms: Windows 8,
Windows Phone 8 and .NET 4.5. The core portable platform project is ```Microsoft.WindowsAzure.Mobile```. The platform-specific assembly projects are
named using a ```Microsoft.WindowsAzure.Mobile.Ext.``` convention. The Windows Phone 8 platform also
include a ```Microsoft.WindowsAzure.Mobile.UI.``` project that contain UI components. To build the Managed Portable Libray:
1. Open the ```sdk\Managed\Microsoft.WindowsAzure.Mobile.Managed.sln``` solution file in Visual Studio 2012.
2. Press F6 to build the solution.
### Running the Tests
The managed portable library ```Microsoft.WindowsAzure.Mobile.Managed.sln``` has a test application for each of the supported platforms: Windows 8,
Windows Phone 8 and .NET 4.5.
1. Open the ```sdk\Managed\Microsoft.WindowsAzure.Mobile.Managed.sln``` solution file in Visual Studio 2012.
2. Right-click on the test project for a given platform in the Solution Explorer and select ```Set as StartUp Project```.
3. Press F5 to run the application in debug mode.
4. An application will appear with a prompt for a runtime Uri and Tags. You can safely ignore this prompt and just click the Start button.
5. The test suite will run and display the results.
## iOS Client SDK
Add a cloud backend to your iOS application in minutes with our iOS client SDK. You can [download the iOS SDK](https://go.microsoft.com/fwLink/?LinkID=266533&clcid=0x409) directly or you can download the source code using the instructions above.
### Prerequisites
The SDK requires Xcode 4.6.3 or greater.
### Building and Referencing the SDK
1. Open the ```sdk\iOS\WindowsAzureMobileServices.xcodeproj``` file in Xcode.
2. Set the active scheme option to ```Framework\iOS Device```.
3. Build the project using Command-B. The ```WindowsAzureMobileServices.framework``` folder should be found in the build output folder under ```Products\-iphoneos```.
4. Drag and drop the ```WindowsAzureMobileServices.framework``` from a Finder window into the Frameworks folder of the Project Navigator panel of your iOS application Xcode project.
### Running the Tests
1. Open the ```sdk\iOS\WindowsAzureMobileServices.xcodeproj``` file in Xcode.
2. Set the active scheme option to ```WindowsAzureMobileServices\* Simulator```.
3. Open the ```Test\WindowsAzureMobileServicesFunctionalTests.m``` file in the Project Navigator panel of Xcode.
4. In the ```settings.plist``` file, set ```TestAppUrl``` and ```TestAppApplicationKey``` to a valid URL and Application Key for a working Mobile Service.
5. Run the tests using Command-U.
## Android SDK
Microsoft Azure Mobile Services can be used with an Android-based device using our Android SDK. You can get the Android SDK in one of the following two ways or you can download the source code using the instructions above.
1. For an Android studio project, include the line `compile 'com.microsoft.azure:azure-mobile-services-android-sdk:2.0.3'` in the dependencies section of build.gradle file of the app
2. Eclipse users can [download the Android SDK](https://go.microsoft.com/fwLink/?LinkID=280126&clcid=0x409) directly or can download the source code using the instructions above.
### Prerequisites
The SDK requires Android Studio.
### Building and Referencing the SDK
1. Open the folder `\azure-mobile-services\sdk\android` using the option `Open an existing Android Studio Project` in Android Studio.
2. Project should be built automatically, In case it does not build, Right click on `sdk` folder and select `Make Module 'sdk'`
3. The file `sdk-release.aar` should be present at `\azure-mobile-services\sdk\android\src\sdk\build\outputs\aar`
4. Rename the file `sdk-release.aar` to `sdk-release.zip`
5. Extract the zip file, `classes.jar` should be present in the root folder.
### Running the Tests
The SDK has a suite of unit tests that you can easily run.
1. Open the folder `\azure-mobile-services\sdk\android` using the option `Open an existing Android Studio Project` in Android Studio.
2. Project should be built automatically, In case it does not build, Right click on `sdk` folder and select `Make Module 'sdk.testapp'`
3. Expand `sdk.testapp` and sub folder `java`
4. Right click on `com.microsoft.windowsazure.mobileservices.sdk.testapp`, Select `Run`, Select `Tests in com.microsoft.windowsazure.mobileservices.sdk.testapp` (with Android tests icon)
## JavaScript SDK
Our JavaScript SDK makes it easy to use our Microsoft Azure Mobile Services in a Windows 8 application or an HTML client. The [Microsoft Azure Mobile Services for WinJS SDK](http://nuget.org/packages/WindowsAzure.MobileServices.WinJS/) is available as a Nuget package or you can download the source for both WinJS and HTML using the instructions above.
### Prerequisites
The Microsoft Azure Mobile Services for WinJS SDK requires Windows 8.1 and Visual Studio 2013 Update 3.
### Building and Referencing the SDK
1. Install Node.js and grunt-cli (globally) for building in Visual Studio
2. Install the Task Runner Explorer(https://visualstudiogallery.msdn.microsoft.com/8e1b4368-4afb-467a-bc13-9650572db708) add on for VS 2013
3. Open the ```sdk\JavaScript\Microsoft.WindowsAzure.Mobile.JS.sln``` file in Visual Studio.
4. Right click on the gruntfile.js in the solution, and select Task Runner Explorer
5. Run the default build option
Alternatively, you can use Grunt from the command line to build the project as well.
For WinJS Windows Store apps, copy the ```Generated/MobileServices[.min].js```, ```Generated/MobileServices.DevIntellisense.js``` and ```Generated/MobileService.pri``` files into your WinJS project. For HTML applications, copy the ```Generated/MobileServices.Web[.min].js``` and the ```Generated/MobileServices.DevIntellisense.js``` files into your HTML\JavaScript project.
### Running the Tests
To run the WinJS Windows Store test app:
1. Open the ```sdk\JavaScript\Microsoft.WindowsAzure.Mobile.JS.sln``` file in Visual Studio.
2. In the Solution Explorer, right-click on the ```Microsoft.WindowsAzure.Mobile.WinJS.Test``` project in the Solution Explorer and select ```Set as StartUp Project```.
3. Press F5 to run the application in debug mode.
4. A Windows Store application will appear with a prompt for a Runtime Uri and Tags. You can safely ignore this prompt and just click the Start button.
5. The test suite will run and display the results.
To run the HTML tests:
1. Open the ```sdk\JavaScript\Microsoft.WindowsAzure.Mobile.JS.sln``` file in Visual Studio.
2. In the Solution Explorer, select the Microsoft.WindowsAzure.Mobile.WinJS.Test project and right-click to select 'View in Browser'.
3. The default browser will launch and run the test HTML application. Some tests may fail because due to an 'Unexpected connection failure'. This is because the test is configured to connect to a Mobile Service that does not exist. These failures can be ignored.
## Useful Resources
* [Quickstarts](https://github.com/Azure/azure-mobile-services-quickstarts)
* [E2E Test Suite](https://github.com/Azure/azure-mobile-services-test)
* [Samples](https://github.com/Azure/mobile-services-samples)
* Tutorials and product overview are available at [Microsoft Azure Mobile Services Developer Center](http://azure.microsoft.com/en-us/develop/mobile).
* Our product team actively monitors the [Mobile Services Developer Forum](http://social.msdn.microsoft.com/Forums/en-US/azuremobile/) to assist you with any troubles.
## Contribute Code or Provide Feedback
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
If you would like to become an active contributor to this project please follow the instructions provided in [Microsoft Azure Projects Contribution Guidelines](http://azure.github.com/guidelines.html).
If you encounter any bugs with the library please file an issue in the [Issues](https://github.com/Azure/azure-mobile-services/issues) section of the project.
================================================
FILE: component/.gitignore
================================================
*.xam
xpkg
*.suo
bin
obj
lib
================================================
FILE: component/Details.md
================================================
Add structured storage, authentication, push notifications and more to your Xamarin based mobile application in minutes using Microsoft Azure Mobile Services.
To get started, follow the tutorial for the appropriate platform:
- [Xamarin.iOS](https://www.windowsazure.com/en-us/develop/mobile/tutorials/get-started-xamarin-ios/)
- [Xamarin.Android](https://www.windowsazure.com/en-us/develop/mobile/tutorials/get-started-xamarin-android/)
To learn about more Mobile Services, visit the [Microsoft Azure Mobile Developer Center](https://www.windowsazure.com/en-us/develop/mobile/).
================================================
FILE: component/GettingStarted.md
================================================
## Getting Started
Follow the tutorial for the appropriate platform:
- [Xamarin.iOS](https://www.windowsazure.com/en-us/develop/mobile/tutorials/get-started-xamarin-ios/)
- [Xamarin.Android](https://www.windowsazure.com/en-us/develop/mobile/tutorials/get-started-xamarin-android/)
### Source Code
- GitHub: https://github.com/WindowsAzure/azure-mobile-services
### Documentation
- Tutorials: https://www.windowsazure.com/en-us/develop/mobile/resources/
- Developer Center: http://www.windowsazure.com/mobile
- API Library: http://msdn.microsoft.com/en-us/library/windowsazure/jj710108.aspx
- Xamarin Mobile Services client framework GitHub Repo: https://github.com/xamarin/azure-mobile-services
### Contact
- Developer Forum: http://social.msdn.microsoft.com/Forums/en-US/azuremobile/threads
- Feature Requests: http://mobileservices.uservoice.com
- Contact: mobileservices@microsoft.com
- Twitter: @paulbatum @joshtwist @cloudnick @chrisrisner @mlunes90
### Legal
- Terms & Conditions: http://www.windowsazure.com/en-us/support/legal/
================================================
FILE: component/License.md
================================================
# Apache License
Version 2.0, January 2004
[http://www.apache.org/licenses/](http://www.apache.org/licenses/)
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
================================================
FILE: component/component.yaml
================================================
id: azure-mobile-services
version: 1.2.1
name: Azure Mobile Services
publisher: Microsoft
publisher-url: http://www.windowsazure.com/en-us/develop/mobile/
summary: Store data in the cloud, authenticate users, and send push notifications.
license: LICENSE.md
details: Details.md
getting-started: GettingStarted.md
icons:
- azure-mobile-services_512x512.png
- azure-mobile-services_128x128.png
libraries:
ios:
- ..\..\bin\Signed\Release\Managed\iOS-Classic\Microsoft.WindowsAzure.Mobile.dll
- ..\..\bin\Signed\Release\Managed\iOS-Classic\Microsoft.WindowsAzure.Mobile.Ext.dll
- ..\..\bin\Signed\Release\Managed\iOS-Classic\Newtonsoft.Json.dll
- ..\..\bin\Signed\Release\Managed\iOS-Classic\System.Net.Http.Extensions.dll
- ..\..\bin\Signed\Release\Managed\iOS-Classic\System.Net.Http.Primitives.dll
ios-unified:
- ..\..\bin\Signed\Release\Managed\iOS\Microsoft.WindowsAzure.Mobile.dll
- ..\..\bin\Signed\Release\Managed\iOS\Microsoft.WindowsAzure.Mobile.Ext.dll
- ..\..\bin\Signed\Release\Managed\iOS\Newtonsoft.Json.dll
- ..\..\bin\Signed\Release\Managed\iOS\System.Net.Http.Extensions.dll
- ..\..\bin\Signed\Release\Managed\iOS\System.Net.Http.Primitives.dll
android:
- ..\..\bin\Signed\Release\Managed\Android\Microsoft.WindowsAzure.Mobile.dll
- ..\..\bin\Signed\Release\Managed\Android\Microsoft.WindowsAzure.Mobile.Ext.dll
- ..\..\bin\Signed\Release\Managed\Android\Newtonsoft.Json.dll
- ..\..\bin\Signed\Release\Managed\Android\System.Net.Http.Extensions.dll
- ..\..\bin\Signed\Release\Managed\Android\System.Net.Http.Primitives.dll
mobile:
- ..\..\bin\Signed\Release\Managed\Portable\Microsoft.WindowsAzure.Mobile.dll
- ..\..\bin\Signed\Release\Managed\Portable\Newtonsoft.Json.dll
samples:
- name: Android Sample
path: samples\androidsample\androidsample.sln
- name: iOS Unified API Sample
path: samples\iOSsample\iOSsample.sln
screenshots:
- screenshots/WAMS-New.PNG
- screenshots/WAMS-SQLdb1.png
- screenshots/WAMS-SQLdb2.png
- screenshots/WAMS-userauth.png
- screenshots/WAMS-push1.png
- screenshots/WAMS-push2.png
- screenshots/WAMS-Create.png
- screenshots/WAMS-Script1.png
- screenshots/WAMS-Script2.png
- screenshots/WAMS-Scheduler2.png
- screenshots/WAMS-Keys.png
- screenshots/WAMS-EmptyData.png
- screenshots/WAMS-DataPermissions.png
================================================
FILE: component/samples/androidsample/androidsample/Assets/AboutAssets.txt
================================================
Any raw assets you want to be deployed with your application can be placed in
this directory (and child directories) and given a Build Action of "AndroidAsset".
These files will be deployed with your package and will be accessible using Android's
AssetManager, like this:
public class ReadAsset : Activity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
InputStream input = Assets.Open ("my_asset.txt");
}
}
Additionally, some Android functions will automatically load asset files:
Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");
================================================
FILE: component/samples/androidsample/androidsample/Properties/AndroidManifest.xml
================================================
================================================
FILE: component/samples/androidsample/androidsample/Properties/AssemblyInfo.cs
================================================
using System.Reflection;
using System.Runtime.CompilerServices;
using Android.App;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle("androidsample")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("billholmes")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("1.0.0")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]
================================================
FILE: component/samples/androidsample/androidsample/Resources/AboutResources.txt
================================================
Images, layout descriptions, binary blobs and string dictionaries can be included
in your application as resource files. Various Android APIs are designed to
operate on the resource IDs instead of dealing with images, strings or binary blobs
directly.
For example, a sample Android app that contains a user interface layout (main.axml),
an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
would keep its resources in the "Resources" directory of the application:
Resources/
drawable/
icon.png
layout/
main.axml
values/
strings.xml
In order to get the build system to recognize Android resources, set the build action to
"AndroidResource". The native Android APIs do not operate directly with filenames, but
instead operate on resource IDs. When you compile an Android application that uses resources,
the build system will package the resources for distribution and generate a class called "R"
(this is an Android convention) that contains the tokens for each one of the resources
included. For example, for the above Resources layout, this is what the R class would expose:
public class R {
public class drawable {
public const int icon = 0x123;
}
public class layout {
public const int main = 0x456;
}
public class strings {
public const int first_string = 0xabc;
public const int second_string = 0xbcd;
}
}
You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main
to reference the layout/main.axml file, or R.strings.first_string to reference the first
string in the dictionary file values/strings.xml.
================================================
FILE: component/samples/androidsample/androidsample/Resources/Resource.designer.cs
================================================
#pragma warning disable 1591
//------------------------------------------------------------------------------
//
// This code was generated by a tool.
// Runtime Version:4.0.30319.34011
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
//------------------------------------------------------------------------------
[assembly: global::Android.Runtime.ResourceDesignerAttribute("androidsample.Resource", IsApplication=true)]
namespace androidsample
{
[System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
public partial class Resource
{
static Resource()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
public static void UpdateIdValues()
{
}
public partial class Attribute
{
static Attribute()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private Attribute()
{
}
}
public partial class Drawable
{
// aapt resource value: 0x7f020000
public const int ic_launcher = 2130837504;
static Drawable()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private Drawable()
{
}
}
public partial class Id
{
// aapt resource value: 0x7f070000
public const int LinearLayout1 = 2131165184;
// aapt resource value: 0x7f070004
public const int buttonAddToDo = 2131165188;
// aapt resource value: 0x7f070006
public const int checkToDoItem = 2131165190;
// aapt resource value: 0x7f070005
public const int listViewToDo = 2131165189;
// aapt resource value: 0x7f070002
public const int loadingProgressBar = 2131165186;
// aapt resource value: 0x7f070007
public const int menu_refresh = 2131165191;
// aapt resource value: 0x7f070003
public const int textNewToDo = 2131165187;
// aapt resource value: 0x7f070001
public const int textViewTitle = 2131165185;
static Id()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private Id()
{
}
}
public partial class Layout
{
// aapt resource value: 0x7f030000
public const int Activity_To_Do = 2130903040;
// aapt resource value: 0x7f030001
public const int Row_List_To_Do = 2130903041;
static Layout()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private Layout()
{
}
}
public partial class Menu
{
// aapt resource value: 0x7f060000
public const int activity_main = 2131099648;
static Menu()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private Menu()
{
}
}
public partial class String
{
// aapt resource value: 0x7f040002
public const int add_button_text = 2130968578;
// aapt resource value: 0x7f040001
public const int add_textbox_hint = 2130968577;
// aapt resource value: 0x7f040000
public const int app_name = 2130968576;
// aapt resource value: 0x7f040005
public const int checkbox_text = 2130968581;
// aapt resource value: 0x7f040004
public const int menu_refresh = 2130968580;
// aapt resource value: 0x7f040003
public const int mobile_services = 2130968579;
static String()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private String()
{
}
}
public partial class Style
{
// aapt resource value: 0x7f050000
public const int AppBaseTheme = 2131034112;
// aapt resource value: 0x7f050001
public const int AppTheme = 2131034113;
static Style()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private Style()
{
}
}
}
}
#pragma warning restore 1591
================================================
FILE: component/samples/androidsample/androidsample/Resources/layout/Activity_To_Do.axml
================================================
================================================
FILE: component/samples/androidsample/androidsample/Resources/layout/Row_List_To_Do.axml
================================================
================================================
FILE: component/samples/androidsample/androidsample/Resources/menu/activity_main.xml
================================================
================================================
FILE: component/samples/androidsample/androidsample/Resources/values/Strings.xml
================================================
androidsampleAdd a ToDo itemAddMobile Services RefreshItem Text
================================================
FILE: component/samples/androidsample/androidsample/Resources/values/styles.xml
================================================
================================================
FILE: component/samples/androidsample/androidsample/Resources/values-v11/styles.xml
================================================
================================================
FILE: component/samples/androidsample/androidsample/Resources/values-v14/styles.xml
================================================
================================================
FILE: component/samples/androidsample/androidsample/ToDoActivity.cs
================================================
using System;
using Android.OS;
using Android.App;
using Android.Views;
using Android.Widget;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.MobileServices;
namespace androidsample
{
[Activity (MainLauncher = true,
Icon="@drawable/ic_launcher", Label="@string/app_name",
Theme="@style/AppTheme")]
public class ToDoActivity : Activity
{
//Mobile Service Client reference
private MobileServiceClient client;
//Mobile Service Table used to access data
private IMobileServiceTable toDoTable;
//Adapter to sync the items list with the view
private ToDoItemAdapter adapter;
//EditText containing the "New ToDo" text
private EditText textNewToDo;
//Progress spinner to use for table operations
private ProgressBar progressBar;
const string applicationURL = @"MOBILE SERVICE URL";
const string applicationKey = @"APPLICATION KEY";
protected override async void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Activity_To_Do);
progressBar = FindViewById (Resource.Id.loadingProgressBar);
// Initialize the progress bar
progressBar.Visibility = ViewStates.Gone;
// Create ProgressFilter to handle busy state
var progressHandler = new ProgressHandler ();
progressHandler.BusyStateChange += (busy) => {
if (progressBar != null)
progressBar.Visibility = busy ? ViewStates.Visible : ViewStates.Gone;
};
try {
CurrentPlatform.Init ();
// Create the Mobile Service Client instance, using the provided
// Mobile Service URL and key
client = new MobileServiceClient (
applicationURL,
applicationKey, progressHandler);
// Get the Mobile Service Table instance to use
toDoTable = client.GetTable ();
textNewToDo = FindViewById (Resource.Id.textNewToDo);
// Create an adapter to bind the items with the view
adapter = new ToDoItemAdapter (this, Resource.Layout.Row_List_To_Do);
var listViewToDo = FindViewById (Resource.Id.listViewToDo);
listViewToDo.Adapter = adapter;
// Load the items from the Mobile Service
await RefreshItemsFromTableAsync ();
} catch (Java.Net.MalformedURLException) {
CreateAndShowDialog (new Exception ("There was an error creating the Mobile Service. Verify the URL"), "Error");
} catch (Exception e) {
CreateAndShowDialog (e, "Error");
}
}
//Initializes the activity menu
public override bool OnCreateOptionsMenu (IMenu menu)
{
MenuInflater.Inflate (Resource.Menu.activity_main, menu);
return true;
}
//Select an option from the menu
public override bool OnOptionsItemSelected (IMenuItem item)
{
if (item.ItemId == Resource.Id.menu_refresh) {
OnRefreshItemsSelected ();
}
return true;
}
// Called when the refresh menu opion is selected
async void OnRefreshItemsSelected ()
{
await RefreshItemsFromTableAsync ();
}
//Refresh the list with the items in the Mobile Service Table
async Task RefreshItemsFromTableAsync ()
{
try {
// Get the items that weren't marked as completed and add them in the
// adapter
var list = await toDoTable.Where (item => item.Complete == false).ToListAsync ();
adapter.Clear ();
foreach (ToDoItem current in list)
adapter.Add (current);
} catch (Exception e) {
CreateAndShowDialog (e, "Error");
}
}
public async Task CheckItem (ToDoItem item)
{
if (client == null) {
return;
}
// Set the item as completed and update it in the table
item.Complete = true;
try {
await toDoTable.UpdateAsync (item);
if (item.Complete)
adapter.Remove (item);
} catch (Exception e) {
CreateAndShowDialog (e, "Error");
}
}
[Java.Interop.Export()]
public async void AddItem (View view)
{
if (client == null || string.IsNullOrWhiteSpace (textNewToDo.Text)) {
return;
}
// Create a new item
var item = new ToDoItem {
Text = textNewToDo.Text,
Complete = false
};
try {
// Insert the new item
await toDoTable.InsertAsync (item);
if (!item.Complete) {
adapter.Add (item);
}
} catch (Exception e) {
CreateAndShowDialog (e, "Error");
}
textNewToDo.Text = "";
}
void CreateAndShowDialog (Exception exception, String title)
{
CreateAndShowDialog (exception.Message, title);
}
void CreateAndShowDialog (string message, string title)
{
AlertDialog.Builder builder = new AlertDialog.Builder (this);
builder.SetMessage (message);
builder.SetTitle (title);
builder.Create ().Show ();
}
class ProgressHandler : DelegatingHandler
{
int busyCount = 0;
public event Action BusyStateChange;
#region implemented abstract members of HttpMessageHandler
protected override async Task SendAsync (HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
//assumes always executes on UI thread
if (busyCount++ == 0 && BusyStateChange != null)
BusyStateChange (true);
var response = await base.SendAsync (request, cancellationToken);
// assumes always executes on UI thread
if (--busyCount == 0 && BusyStateChange != null)
BusyStateChange (false);
return response;
}
#endregion
}
}
}
================================================
FILE: component/samples/androidsample/androidsample/ToDoItem.cs
================================================
using System;
using Newtonsoft.Json;
namespace androidsample
{
public class ToDoItem
{
public string Id { get; set; }
[JsonProperty(PropertyName = "text")]
public string Text { get; set; }
[JsonProperty(PropertyName = "complete")]
public bool Complete { get; set; }
}
public class ToDoItemWrapper : Java.Lang.Object
{
public ToDoItemWrapper (ToDoItem item)
{
ToDoItem = item;
}
public ToDoItem ToDoItem { get; private set; }
}
}
================================================
FILE: component/samples/androidsample/androidsample/ToDoItemAdapter.cs
================================================
using System;
using Android.App;
using Android.Views;
using Android.Widget;
using System.Collections.Generic;
namespace androidsample
{
public class ToDoItemAdapter : BaseAdapter
{
Activity activity;
int layoutResourceId;
List items = new List ();
public ToDoItemAdapter (Activity activity, int layoutResourceId)
{
this.activity = activity;
this.layoutResourceId = layoutResourceId;
}
//Returns the view for a specific item on the list
public override View GetView (int position, Android.Views.View convertView, Android.Views.ViewGroup parent)
{
var row = convertView;
var currentItem = this [position];
CheckBox checkBox;
if (row == null) {
var inflater = activity.LayoutInflater;
row = inflater.Inflate (layoutResourceId, parent, false);
checkBox = row.FindViewById (Resource.Id.checkToDoItem);
checkBox.CheckedChange += async (sender, e) => {
var cbSender = sender as CheckBox;
if (cbSender != null && cbSender.Tag is ToDoItemWrapper && cbSender.Checked) {
cbSender.Enabled = false;
if (activity is ToDoActivity)
await ((ToDoActivity)activity).CheckItem ((cbSender.Tag as ToDoItemWrapper).ToDoItem);
}
};
} else
checkBox = row.FindViewById (Resource.Id.checkToDoItem);
checkBox.Text = currentItem.Text;
checkBox.Checked = false;
checkBox.Enabled = true;
checkBox.Tag = new ToDoItemWrapper (currentItem);
return row;
}
public void Add (ToDoItem item)
{
items.Add (item);
NotifyDataSetChanged ();
}
public void Clear ()
{
items.Clear ();
NotifyDataSetChanged ();
}
public void Remove (ToDoItem item)
{
items.Remove (item);
NotifyDataSetChanged ();
}
#region implemented abstract members of BaseAdapter
public override long GetItemId (int position)
{
return position;
}
public override int Count {
get {
return items.Count;
}
}
public override ToDoItem this [int position] {
get {
return items [position];
}
}
#endregion
}
}
================================================
FILE: component/samples/androidsample/androidsample/androidsample.csproj
================================================
DebugAnyCPU10.0.02.0{8E1FCCF4-1FA7-4C23-86B0-19C78B155AA3}{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}LibraryandroidsampleTrueResources\Resource.designer.csResourceResourcesAssetsandroidsampleProperties\AndroidManifest.xmltruearmeabi,armeabi-v7a,x86truefullfalsebin\DebugDEBUG;prompt4Nonefalsefulltruebin\Releaseprompt4falsefalsearmeabi,armeabi-v7aFalse..\..\..\lib\android\Microsoft.WindowsAzure.Mobile.dllFalse..\..\..\lib\android\Microsoft.WindowsAzure.Mobile.Ext.dllFalse..\..\..\lib\android\Newtonsoft.Json.dllFalse..\..\..\lib\android\System.Net.Http.Extensions.dllFalse..\..\..\lib\android\System.Net.Http.Primitives.dll
================================================
FILE: component/samples/androidsample/androidsample/app.config
================================================
================================================
FILE: component/samples/androidsample/androidsample.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "androidsample", "androidsample\androidsample.csproj", "{8E1FCCF4-1FA7-4C23-86B0-19C78B155AA3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8E1FCCF4-1FA7-4C23-86B0-19C78B155AA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8E1FCCF4-1FA7-4C23-86B0-19C78B155AA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8E1FCCF4-1FA7-4C23-86B0-19C78B155AA3}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{8E1FCCF4-1FA7-4C23-86B0-19C78B155AA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8E1FCCF4-1FA7-4C23-86B0-19C78B155AA3}.Release|Any CPU.Build.0 = Release|Any CPU
{8E1FCCF4-1FA7-4C23-86B0-19C78B155AA3}.Release|Any CPU.Deploy.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = androidsample\androidsample.csproj
EndGlobalSection
EndGlobal
================================================
FILE: component/samples/iOSsample/iOSsample/AppDelegate.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using Foundation;
using UIKit;
namespace iOSsample
{
// The UIApplicationDelegate for the application. This class is responsible for launching the
// User Interface of the application, as well as listening (and optionally responding) to
// application events from iOS.
[Foundation.Register("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
// class-level declarations
public override UIWindow Window {get; set;}
}
}
================================================
FILE: component/samples/iOSsample/iOSsample/Info.plist
================================================
UIDeviceFamily12UISupportedInterfaceOrientationsUIInterfaceOrientationPortraitUIInterfaceOrientationLandscapeLeftUIInterfaceOrientationLandscapeRightUISupportedInterfaceOrientations~ipadUIInterfaceOrientationPortraitUIMainStoryboardFileMainStoryboard_iPhoneUIMainStoryboardFile~ipadMainStoryboard_iPadMinimumOSVersion7.0CFBundleIconFilesIcon.pngIcon@2x.pngIcon-72.pngIcon-72@2x.pngDefault.pngDefault@2x.pngDefault-568h@2x.pngDefault-Landscape.pngDefault-Landscape@2x.pngDefault-Portrait.pngDefault-Portrait@2x.pngCFBundleDisplayNameiOSsampleCFBundleIdentifiernet.azure-mobile.iOSsampleCFBundleVersion1.0NSMainNibFileNSMainNibFile~ipad
================================================
FILE: component/samples/iOSsample/iOSsample/Main.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using Foundation;
using UIKit;
namespace iOSsample
{
public class Application
{
// This is the main entry point of the application.
static void Main (string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main (args, null, "AppDelegate");
}
}
}
================================================
FILE: component/samples/iOSsample/iOSsample/MainStoryboard_iPad.storyboard
================================================
================================================
FILE: component/samples/iOSsample/iOSsample/MainStoryboard_iPhone.storyboard
================================================
================================================
FILE: component/samples/iOSsample/iOSsample/QSTodoListViewController.cs
================================================
// This file has been autogenerated from parsing an Objective-C header file added in Xcode.
using System;
using UIKit;
using Foundation;
using System.Threading.Tasks;
namespace iOSsample
{
public partial class QSTodoListViewController : UITableViewController
{
QSTodoService todoService;
bool useRefreshControl = false;
public QSTodoListViewController (IntPtr handle) : base (handle)
{
}
public override async void ViewDidLoad ()
{
base.ViewDidLoad ();
try
{
todoService = new QSTodoService();
}
catch (UriFormatException)
{
var alert = new UIAlertView("Error", "Please make sure you update the applicationURL and applicationKey to match the mobile service you have created.", null, "OK");
alert.Show();
return;
}
todoService.BusyUpdate += (bool busy) => {
if (busy)
activityIndicator.StartAnimating ();
else
activityIndicator.StopAnimating ();
};
await RefreshAsync ();
AddRefreshControl ();
}
async Task RefreshAsync ()
{
// only activate the refresh control if the feature is available
if (useRefreshControl)
RefreshControl.BeginRefreshing ();
await todoService.RefreshDataAsync ();
if (useRefreshControl)
RefreshControl.EndRefreshing ();
TableView.ReloadData ();
}
#region UITableView methods
public override nint RowsInSection (UITableView tableview, nint section)
{
if (todoService == null || todoService.Items == null)
return 0;
return todoService.Items.Count;
}
public override nint NumberOfSections (UITableView tableView)
{
return 1;
}
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
const string CellIdentifier = @"Cell";
var cell = tableView.DequeueReusableCell (CellIdentifier);
if (cell == null) {
cell = new UITableViewCell (UITableViewCellStyle.Default, CellIdentifier);
}
// Set the label on the cell and make sure the label color is black (in case this cell
// has been reused and was previously greyed out
var label = (UILabel)cell.ViewWithTag ((nint)1);
label.TextColor = UIColor.Black;
label.Text = todoService.Items [indexPath.Row].Text;
return cell;
}
public override string TitleForDeleteConfirmation (UITableView tableView, NSIndexPath indexPath)
{
// Customize the Delete button to say "complete"
return @"complete";
}
public override UITableViewCellEditingStyle EditingStyleForRow (UITableView tableView, NSIndexPath indexPath)
{
// Find the item that is about to be edited
var item = todoService.Items [indexPath.Row];
// If the item is complete, then this is just pending upload. Editing is not allowed
if (item.Complete)
return UITableViewCellEditingStyle.None;
// Otherwise, allow the delete button to appear
return UITableViewCellEditingStyle.Delete;
}
async public override void CommitEditingStyle (UITableView tableView, UITableViewCellEditingStyle editingStyle, NSIndexPath indexPath)
{
// Find item that was commited for editing (completed)
var item = todoService.Items [indexPath.Row];
// Change the appearance to look greyed out until we remove the item
var label = (UILabel)TableView.CellAt (indexPath).ViewWithTag (1);
label.TextColor = UIColor.Gray;
// Ask the todoService to set the item's complete value to YES, and remove the row if successful
await todoService.CompleteItemAsync (item);
// Remove the row from the UITableView
tableView.DeleteRows (new [] { indexPath }, UITableViewRowAnimation.Top);
}
#endregion
#region UI Actions
async partial void OnAdd (NSObject sender)
{
if (string.IsNullOrWhiteSpace (itemText.Text))
return;
var newItem = new ToDoItem {
Text = itemText.Text,
Complete = false
};
await todoService.InsertTodoItemAsync (newItem);
var index = todoService.Items.FindIndex (item => item.Id == newItem.Id);
TableView.InsertRows (new [] { NSIndexPath.FromItemSection (index, 0) },
UITableViewRowAnimation.Top);
itemText.Text = "";
}
#endregion
#region UITextFieldDelegate methods
[Foundation.Export("textFieldShouldReturn:")]
public virtual bool ShouldReturn (UITextField textField)
{
textField.ResignFirstResponder ();
return true;
}
#endregion
#region * iOS Specific Code
// This method will add the UIRefreshControl to the table view if
// it is available, ie, we are running on iOS 6+
void AddRefreshControl ()
{
if (UIDevice.CurrentDevice.CheckSystemVersion (6, 0)) {
// the refresh control is available, let's add it
RefreshControl = new UIRefreshControl ();
RefreshControl.ValueChanged += async (sender, e) => {
await RefreshAsync ();
};
useRefreshControl = true;
}
}
#endregion
}
}
================================================
FILE: component/samples/iOSsample/iOSsample/QSTodoListViewController.designer.cs
================================================
// WARNING
//
// This file has been generated automatically by Xamarin Studio to store outlets and
// actions made in the Xcode designer. If it is removed, they will be lost.
// Manual changes to this file may not be handled correctly.
//
using Foundation;
namespace iOSsample
{
[Foundation.Register("QSTodoListViewController")]
partial class QSTodoListViewController
{
[Foundation.Outlet]
UIKit.UIActivityIndicatorView activityIndicator { get; set; }
[Foundation.Outlet]
UIKit.UITextField itemText { get; set; }
[Foundation.Action("OnAdd:")]
partial void OnAdd (Foundation.NSObject sender);
void ReleaseDesignerOutlets ()
{
if (itemText != null) {
itemText.Dispose ();
itemText = null;
}
if (activityIndicator != null) {
activityIndicator.Dispose ();
activityIndicator = null;
}
}
}
}
================================================
FILE: component/samples/iOSsample/iOSsample/QSTodoService.cs
================================================
using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.Collections.Generic;
using Microsoft.WindowsAzure.MobileServices;
namespace iOSsample
{
public class QSTodoService : DelegatingHandler
{
const string applicationURL = @"MOBILE SERVICE URL";
const string applicationKey = @"APPLICATION KEY";
MobileServiceClient client;
IMobileServiceTable todoTable;
int busyCount = 0;
public event Action BusyUpdate;
public QSTodoService ()
{
CurrentPlatform.Init ();
// Initialize the Mobile Service client with your URL and key
client = new MobileServiceClient (applicationURL, applicationKey, this);
// Create an MSTable instance to allow us to work with the TodoItem table
todoTable = client.GetTable ();
}
public List Items { get; private set;}
async public Task> RefreshDataAsync ()
{
try {
// This code refreshes the entries in the list view by querying the TodoItems table.
// The query excludes completed TodoItems
Items = await todoTable
.Where (todoItem => todoItem.Complete == false).ToListAsync ();
} catch (MobileServiceInvalidOperationException e) {
Console.Error.WriteLine (@"ERROR {0}", e.Message);
return null;
}
return Items;
}
public async Task InsertTodoItemAsync (ToDoItem todoItem)
{
try {
// This code inserts a new TodoItem into the database. When the operation completes
// and Mobile Services has assigned an Id, the item is added to the CollectionView
await todoTable.InsertAsync (todoItem);
Items.Add (todoItem);
} catch (MobileServiceInvalidOperationException e) {
Console.Error.WriteLine (@"ERROR {0}", e.Message);
}
}
public async Task CompleteItemAsync (ToDoItem item)
{
try {
// This code takes a freshly completed TodoItem and updates the database. When the MobileService
// responds, the item is removed from the list
item.Complete = true;
await todoTable.UpdateAsync (item);
Items.Remove (item);
} catch (MobileServiceInvalidOperationException e) {
Console.Error.WriteLine (@"ERROR {0}", e.Message);
}
}
void Busy (bool busy)
{
// assumes always executes on UI thread
if (busy) {
if (busyCount++ == 0 && BusyUpdate != null)
BusyUpdate (true);
} else {
if (--busyCount == 0 && BusyUpdate != null)
BusyUpdate (false);
}
}
#region implemented abstract members of HttpMessageHandler
protected override async Task SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
Busy (true);
var response = await base.SendAsync (request, cancellationToken);
Busy (false);
return response;
}
#endregion
}
}
================================================
FILE: component/samples/iOSsample/iOSsample/ToDoItem.cs
================================================
using System;
using Newtonsoft.Json;
namespace iOSsample
{
public class ToDoItem
{
public string Id { get; set; }
[JsonProperty(PropertyName = "text")]
public string Text { get; set; }
[JsonProperty(PropertyName = "complete")]
public bool Complete { get; set; }
}
}
================================================
FILE: component/samples/iOSsample/iOSsample/app.config
================================================
================================================
FILE: component/samples/iOSsample/iOSsample/iOSsample.csproj
================================================
DebugiPhoneSimulator10.0.02.0{07F1CD1B-626F-4BE5-9840-97B44CBB94C9}{FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}ExeiOSsampleResourcesiOSsampletruefullfalsebin\iPhoneSimulator\DebugDEBUG;prompt4SdkOnlyfalseTrue8.1FalseFalseTrueDefault, i386FalseFalseFalseFalseFalsefulltruebin\iPhoneSimulator\Releaseprompt4Nonefalsetruefullfalsebin\iPhone\DebugDEBUG;prompt4truefalseiPhone Developerfulltruebin\iPhone\Releaseprompt4iPhone Developerfalsefulltruebin\iPhone\Ad-Hocprompt4iPhone Developertruefalsefulltruebin\iPhone\AppStoreprompt4iPhone DistributionfalseAutomatic:AppStoreFalse..\..\..\lib\ios-unified\Microsoft.WindowsAzure.Mobile.dllFalse..\..\..\lib\ios-unified\Microsoft.WindowsAzure.Mobile.Ext.dllFalse..\..\..\lib\ios-unified\Newtonsoft.Json.dllFalse..\..\..\lib\ios-unified\System.Net.Http.Extensions.dllFalse..\..\..\lib\ios-unified\System.Net.Http.Primitives.dllQSTodoListViewController.cs
================================================
FILE: component/samples/iOSsample/iOSsample.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.30110.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOSsample", "iOSsample\iOSsample.csproj", "{07F1CD1B-626F-4BE5-9840-97B44CBB94C9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|iPhone = Debug|iPhone
Debug|iPhoneSimulator = Debug|iPhoneSimulator
Release|iPhone = Release|iPhone
Release|iPhoneSimulator = Release|iPhoneSimulator
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{07F1CD1B-626F-4BE5-9840-97B44CBB94C9}.Debug|iPhone.ActiveCfg = Debug|iPhone
{07F1CD1B-626F-4BE5-9840-97B44CBB94C9}.Debug|iPhone.Build.0 = Debug|iPhone
{07F1CD1B-626F-4BE5-9840-97B44CBB94C9}.Debug|iPhone.Deploy.0 = Debug|iPhone
{07F1CD1B-626F-4BE5-9840-97B44CBB94C9}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{07F1CD1B-626F-4BE5-9840-97B44CBB94C9}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{07F1CD1B-626F-4BE5-9840-97B44CBB94C9}.Debug|iPhoneSimulator.Deploy.0 = Debug|iPhoneSimulator
{07F1CD1B-626F-4BE5-9840-97B44CBB94C9}.Release|iPhone.ActiveCfg = Release|iPhone
{07F1CD1B-626F-4BE5-9840-97B44CBB94C9}.Release|iPhone.Build.0 = Release|iPhone
{07F1CD1B-626F-4BE5-9840-97B44CBB94C9}.Release|iPhone.Deploy.0 = Release|iPhone
{07F1CD1B-626F-4BE5-9840-97B44CBB94C9}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{07F1CD1B-626F-4BE5-9840-97B44CBB94C9}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
{07F1CD1B-626F-4BE5-9840-97B44CBB94C9}.Release|iPhoneSimulator.Deploy.0 = Release|iPhoneSimulator
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = iOSsample\iOSsample.csproj
EndGlobalSection
EndGlobal
================================================
FILE: docs/README.md
================================================
# Azure Mobile Services Documentation
Azure Mobile Services has been deprecated. This documentation is a copy of the
documentation at the point at which the service was deprecated. No further
updates will be made to these documents.
This service has been superseded by Azure App Service Mobile Apps. We recommend
using Azure Mobile Apps for all new mobile backend deployments. Read
[this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/)
to learn more about the pending deprecation of this service.
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
List of documents (from the original left-hand navigation)
Additional documents can be accessed by browsing the directory.
* Get started
* [Get started with iOS](mobile-services-ios-get-started.md)
* [Get started with Xamarin Android](partner-xamarin-mobile-services-android-get-started.md)
* [Get started with Xamarin iOS](partner-xamarin-mobile-services-ios-get-started.md)
* [Get started with Android](mobile-services-android-get-started.md)
* [Get started with Windows](mobile-services-dotnet-backend-windows-store-dotnet-get-started.md)
* Store data
* [Connect your app to Table storage](mobile-services-dotnet-backend-store-data-table-storage.md)
* [Connect your app to DocumentDB](http://giventocode.com/how-to-use-azure-documentdb-with-azure-mobile-services#.VOZ7csJ0x9C)
* [Connect your app to an on-premise SQL Database](mobile-services-dotnet-backend-hybrid-connections-get-started.md)
* [Connect your app to an existing SQL Database](mobile-services-dotnet-backend-use-existing-sql-database.md)
* Enable offline & Sync
* [Sync your app data and work offline](mobile-services-ios-get-started-offline-data.md)
* [Handle conflicts with offline data Sync](mobile-services-ios-handling-conflicts-offline-data.md)
* Authentication users
* [Add Active Directory authentication to your app](mobile-services-dotnet-backend-ios-adal-sso-authentication.md)
* [Add Facebook, Google or Twitter authentication to your app](mobile-services-ios-get-started-users.md)
* [Add custom authentication to your app](mobile-services-dotnet-backend-get-started-custom-authentication.md)
* Send push notifications
* [Add push notifications to your app](mobile-services-javascript-backend-ios-get-started-push.md)
* [Send push notifications to authenticated users](mobile-services-javascript-backend-ios-push-notifications-app-users.md)
* [Send personalized and localized push notifications](https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-ios-xplat-localized-apns-push-notification/)
* [Troubleshoot sending push](https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-push-notification-fixer/)
* How to manage
* [Define a custom endpoint](mobile-services-javascript-backend-define-custom-api.md)
* [Use multiple clients with a single mobile service](mobile-services-how-to-use-multiple-clients-single-service.md)
* [Build scalable apps that talk to Azure SQL database](mobile-services-sql-scale-guidance.md)
* [Prepare for disaster recovery](mobile-services-disaster-recovery.md)
* Automate
* [Deploy and manage a mobile service using command-line Tools](mobile-services-manage-command-line-interface.md)
* [Deploy a mobile service using source control](mobile-services-store-scripts-source-control.md)
* [Execute backend tasks on a schedule](mobile-services-schedule-recurring-tasks.md)
================================================
FILE: docs/mobile-services-android-get-started-data.md
================================================
# Add Mobile Services to an existing Android app (JavaScript backend)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
## Summary
This topic shows you how to use Azure Mobile Services to add persistent data to an Android app. In this tutorial, you will download an app that stores data in memory, create a new mobile service, integrate the app with the mobile service so that it stores and updates data in Azure Mobile Services instead of locally, and then use the Azure classic portal to view changes to data that were made by running the app.
This tutorial helps you understand in more detail how Azure Mobile Services can store and retrieve data from an Android app. So it walks you through many of the steps that are already completed for you in the Mobile Services quickstart tutorial. If this is your first experience with Mobile Services, consider first completing the tutorial [Get started with Mobile Services](mobile-services-android-get-started.md).
## Prerequisites
To complete this tutorial, you need the following:
- an Azure account. If you don't have an account, you can create a free trial account in just a couple of minutes. For details, see [Azure Free Trial](http://azure.microsoft.com/pricing/free-trial/?WT.mc_id=AED8DE357).
- the [Azure Mobile Services Android SDK];
- the [Android Studio integrated development environment](https://developer.android.com/sdk/index.html), which includes the Android SDK; and Android 4.2 or a later version. The downloaded GetStartedWithData project requires Android 4.2 or a later version. However, the Mobile Services SDK requires only Android 2.2 or a later version.
## Sample Code
To see the completed source code, go [here](https://github.com/Azure/mobile-services-samples/tree/master/GettingStartedWithData/AndroidStudio).
## Download the GetStartedWithData project
### Get the sample code
This tutorial is built on **GetStartedWithData**, which is an Android app. The UI for this app is identical to the one in the Mobile Services Android quickstart, except that items that are added to the list are stored locally in memory. You will add the code needed to persist the data to storage.
1. Download the samples repository from gitHub by clicking here and then Click **Download ZIP**.
2. Unzip the downloaded file and make a note of its location, or move it to your Android Studio projects directory.
3. Open Android Studio. If you are working with a different project and it appears, close the project (**File => Close Project**).
4. Select **Open an existing Android Studio project**, browse to the project location in the *AndroidStudio* folder of *GettingStartedWithData*, and then click **OK.**

The project is now ready for you to work with.
### Inspect and run the sample code
1. In Project Explorer, expand **app** => **src** => **main** => **java** => **com.example.GetStartedWithData** and then open the *ToDoActivity.java* file.

Notice that there are `//TODO` comments that specify the steps you must take to make this app work with your mobile service.
2. From the **Run** menu, click **Run app**.
3. The **Choose Device** dialog will appear.

> [AZURE.NOTE] You can run this project using an Android phone, or using the Android emulator. Running with an Android phone requires you to download a phone-specific USB driver.
>
> To run the project in the Android emulator, you must define a least one Android Virtual Device (AVD). Use the AVD Manager to create and manage these devices.
4. Choose either a connected device, or *Launch Emulator*.
5. When the app appears, type meaningful text, such as _Complete the tutorial_, and then click **Add**.

Notice that the saved text is stored in an in-memory collection and displayed in the list below.
## Create a new mobile service in the Azure classic portal
Next, you will create a new mobile service to replace the in-memory list for data storage. Follow these steps to create a new mobile service.
1. Log into the [Azure classic portal](https://manage.windowsazure.com/).
2. At the bottom of the navigation pane, click **+NEW**.

3. Expand **Compute** and **Mobile Service**, then click **Create**.

This displays the **New Mobile Service** dialog.
4. In the **Create a mobile service** page, select **Create a free 20 MB SQL Database**, then type a subdomain name for the new mobile service in the **URL** textbox and wait for name verification. Once name verification completes, click the right arrow button to go to the next page.

This displays the **Specify database settings** page.
> [AZURE.NOTE] As part of this tutorial, you create a new SQL Database instance and server. You can reuse this new database and administer it as you would any other SQL Database instance. If you already have a database in the same region as the new mobile service, you can instead choose **Use existing Database** and then select that database. The use of a database in a different region is not recommended because of additional bandwidth costs and higher latencies.
5. In **Name**, type the name of the new database, then type **Login name**, which is the administrator login name for the new SQL Database server, type and confirm the password, and click the check button to complete the process.

> [AZURE.NOTE] When the password that you supply does not meet the minimum requirements or when there is a mismatch, a warning is displayed.
>
> We recommend that you make a note of the administrator login name and password that you specify; you will need this information to reuse the SQL Database instance or the server in the future.
You have now created a new mobile service that can be used by your mobile apps. Next, you will add a new table in which to store app data. This table will be used by the app in place of the in-memory collection.
## Add a new table to the mobile service
To be able to store app data in the new mobile service, you must first create a new table in the associated SQL Database instance.
1. In the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services**, and then click the mobile service that you just created.
2. Click the **Data** tab, then click **+Create**.
This displays the **Create new table** dialog.
3. In **Table name** type _TodoItem_, then click the check button. This creates a new storage table **TodoItem** with the default permissions set. This means that anyone with the application key, which is distributed with your app, can access and change data in the table.
>[AZURE.NOTE] The same table name is used in Mobile Services quickstart. However, each table is created in a schema that is specific to a given mobile service. This is to prevent data collisions when multiple mobile services use the same database.
4. Click the new **TodoItem** table and verify that there are no data rows.
5. Click the **Columns** tab. Verify that the following default columns are automatically created for you:
Column Name
Type
Index
id
string
Indexed
__createdAt
date
Indexed
__updatedAt
date
-
__version
timestamp (MSSQL)
-
This is the minimum requirement for a table in Mobile Services.
> [AZURE.NOTE] When dynamic schema is enabled on your mobile service, new columns are created automatically when JSON objects are sent to the mobile service by an insert or update operation.
You are now ready to use the new mobile service as data storage for the app.
## Update the app to use the mobile service for data access
Now that your mobile service is ready, you can update the app to store items in Mobile Services instead of the local collection.
1. Verify that you have the following lines in the **dependencies** tag in the *build.gradle (Module app)* file, and if not add them. This adds references to the Mobile Services Android Client SDK.
compile 'com.android.support:support-v4:21.0.3'
compile 'com.google.code.gson:gson:2.2.2'
compile 'com.google.guava:guava:18.0'
compile 'com.microsoft.azure:azure-mobile-services-android-sdk:2.0.2+'
2. Now rebuild the project by clicking on **Sync Project with Gradle Files**.
3. Open the AndroidManifest.xml file and add the following line, which enables the app to access Mobile Services in Azure.
4. In Project Explorer, open the TodoActivity.java file located in the **GetStartedWithData => app => src => java** folder, and uncomment the following lines of code:
import java.net.MalformedURLException;
import android.os.AsyncTask;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.microsoft.windowsazure.mobileservices.MobileServiceClient;
import com.microsoft.windowsazure.mobileservices.MobileServiceList;
import com.microsoft.windowsazure.mobileservices.http.NextServiceFilterCallback;
import com.microsoft.windowsazure.mobileservices.http.ServiceFilter;
import com.microsoft.windowsazure.mobileservices.http.ServiceFilterRequest;
import com.microsoft.windowsazure.mobileservices.http.ServiceFilterResponse;
import com.microsoft.windowsazure.mobileservices.table.MobileServiceTable;
5. Comment out the following lines:
import java.util.ArrayList;
import java.util.List;
6. We will remove the in-memory list currently used by the app, so we can replace it with a mobile service. In the **ToDoActivity** class, comment out the following line of code, which defines the existing **toDoItemList** list.
public List toDoItemList = new ArrayList();
7. Save the file, and the project will indicate build errors. Search for the three remaining locations where the `toDoItemList` variable is used and comment out the sections indicated. This fully removes the in-memory list.
8. We now add our mobile service. Uncomment the following lines of code:
private MobileServiceClient mClient;
private private MobileServiceTable mToDoTable;
9. Find the *ProgressFilter* class at the bottom of the file and uncomment it. This class displays a 'loading' indicator while *MobileServiceClient* is running network operations.
10. In the Azure classic portal, click **Mobile Services**, and then click the mobile service you just created.
11. Click the **Dashboard** tab and make a note of the **Site URL**, then click **Manage keys** and make a note of the **Application key**.

You will need these values when accessing the mobile service from your app code.
12. In the **onCreate** method, uncomment the following lines of code that define the **MobileServiceClient** variable:
try {
// Create the Mobile Service Client instance, using the provided
// Mobile Service URL and key
mClient = new MobileServiceClient(
"MobileServiceUrl",
"AppKey",
this).withFilter(new ProgressFilter());
// Get the Mobile Service Table instance to use
mToDoTable = mClient.getTable(ToDoItem.class);
} catch (MalformedURLException e) {
createAndShowDialog(new Exception("There was an error creating the Mobile Service. Verify the URL"), "Error");
}
This creates a new instance of *MobileServiceClient* that is used to access your mobile service. It also creates the *MobileServiceTable* instance that is used to proxy data storage in the mobile service.
13. In the code above, replace `MobileServiceUrl` and `AppKey` with the URL and application key from your mobile service, in that order.
14. Uncommment these lines of the **checkItem** method:
new AsyncTask() {
@Override
protected Void doInBackground(Void... params) {
try {
mToDoTable.update(item).get();
runOnUiThread(new Runnable() {
public void run() {
if (item.isComplete()) {
mAdapter.remove(item);
}
refreshItemsFromTable();
}
});
} catch (Exception exception) {
createAndShowDialog(exception, "Error");
}
return null;
}
}.execute();
This sends an item update to the mobile service and removes checked items from the adapter.
15. Uncommment these lines of the **addItem** method:
// Insert the new item
new AsyncTask() {
@Override
protected Void doInBackground(Void... params) {
try {
mToDoTable.insert(item).get();
if (!item.isComplete()) {
runOnUiThread(new Runnable() {
public void run() {
mAdapter.add(item);
}
});
}
} catch (Exception exception) {
createAndShowDialog(exception, "Error");
}
return null;
}
}.execute();
This code creates a new item and inserts it into the table in the remote mobile service.
16. Uncommment these lines of the **refreshItemsFromTable** method:
// Get the items that weren't marked as completed and add them in the adapter
new AsyncTask() {
@Override
protected Void doInBackground(Void... params) {
try {
final MobileServiceList result = mToDoTable.where().field("complete").eq(false).execute().get();
runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.clear();
for (ToDoItem item : result) {
mAdapter.add(item);
}
}
});
} catch (Exception exception) {
createAndShowDialog(exception, "Error");
}
return null;
}
}.execute();
This queries the mobile service and returns all items that are not marked as complete. Items are added to the adapter for binding.
## Test the app against your new mobile service
Now that the app has been updated to use Mobile Services for back end storage, you can test it against Mobile Services, using either the Android emulator or an Android phone.
1. From the **Run** menu, click **Run app** to start the project.
This executes your app, built with the Android SDK, that uses the client library to send a query that returns items from your mobile service.
5. As before, type meaningful text, then click **Add**.
This sends a new item as an insert to the mobile service.
3. In the [Azure classic portal], click **Mobile Services**, and then click your mobile service.
4. Click the **Data** tab, then click **Browse**.
![][9]
Notice that the **TodoItem** table now contains data, with some values generated by Mobile Services, and that columns have been automatically added to the table to match the TodoItem class in the app.
This concludes the **Get started with data** tutorial for Android.
## Troubleshooting
### Verify Android SDK Version
Because of ongoing development, the Android SDK version installed in Android Studio might not match the version in the code. The Android SDK referenced in this tutorial is version 21, the latest at the time of writing. The version number may increase as new releases of the SDK appear, and we recomend using the latest version available.
Two symptoms of version mismatch are:
1. When you Build or Rebuild the project, you may get Gradle error messages like "**failed to find target Google Inc.:Google APIs:n**".
2. Standard Android objects in code that should resolve based on `import` statements may be generating error messages.
If either of these appear, the version of the Android SDK installed in Android Studio might not match the SDK target of the downloaded project. To verify the version, make the following changes:
1. In Android Studio, click **Tools** => **Android** => **SDK Manager**. If you have not installed the latest version of the SDK Platform, then click to install it. Make a note of the version number.
2. In the Project Explorer tab, under **Gradle Scripts**, open the file **build.gradle (modeule: app)**. Ensure that the **compileSdkVersion** and **buildToolsVersion** are set to the latest SDK version installed. The tags might look like this:
compileSdkVersion 'Google Inc.:Google APIs:21'
buildToolsVersion "21.1.2"
3. In the Android Studio Project Explorer right-click the project node, choose **Properties**, and in the left column choose **Android**. Ensure that the **Project Build Target** is set to the same SDK version as the **targetSdkVersion**.
4. In Android Studio, the manifest file is no longer used to specify the target SDK and minimum SDK version, unlike the case with Eclipse.
## Next steps
This tutorial demonstrated the basics of enabling an Android app to work with data in Mobile Services. Try these other Android tutorials:
* [Get started with authentication](mobile-services-android-get-started-users.md)
Learn how to authenticate users of your app.
* [Get started with push notifications](mobile-services-javascript-backend-android-get-started-push.md)
Learn how to send a very basic push notification to your app with Mobile Services.
[Download the Android app project]: #download-app
[Create the mobile service]: #create-service
[Add a data table for storage]: #add-table
[Update the app to use Mobile Services]: #update-app
[Test the app against Mobile Services]: #test-app
[Next Steps]:#next-steps
[8]: ./media/mobile-services-android-get-started-data/mobile-dashboard-tab.png
[9]: ./media/mobile-services-android-get-started-data/mobile-todoitem-data-browse.png
[12]: ./media/mobile-services-android-get-started-data/mobile-eclipse-project.png
[13]: ./media/mobile-services-android-get-started-data/mobile-quickstart-startup-android.png
[14]: ./media/mobile-services-android-get-started-data/mobile-services-import-android-workspace.png
[15]: ./media/mobile-services-android-get-started-data/mobile-services-import-android-project.png
[Mobile Services Android SDK]: http://aka.ms/Iajk6q
[Azure classic portal]: https://manage.windowsazure.com/
[Azure Mobile Services Android SDK]: http://aka.ms/Iajk6q
[GitHub]: http://go.microsoft.com/fwlink/p/?LinkID=282122
[Android SDK]: https://go.microsoft.com/fwLink/p/?LinkID=280125
================================================
FILE: docs/mobile-services-android-get-started-offline-data.md
================================================
# Add Offline Data Sync to your Android Mobile Services app
> [AZURE.SELECTOR]
- [Android)](mobile-services-android-get-started-offline-data.md)
- [iOS](mobile-services-ios-get-started-offline-data.md)
- [Windows](mobile-services-windows-store-dotnet-get-started-offline-data.md)
- [Xamarin.Android](mobile-services-xamarin-android-get-started-offline-data.md)
- [Xamarin.iOS](mobile-services-xamarin-ios-get-started-offline-data.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
## Summary
Mobile apps can lose network connectivity when moving to an area without service, or due to network issues. For example, a construction industry app used at a remote construction site might need to enter scheduling data that is synced up to Azure later. With Azure Mobile Services offline sync, you can keep working when network connectivity is lost, which is essential to many mobile apps. With offline sync, you work with a local copy of your Azure SQL Server table, and periodically re-sync the two.
In this tutorial, you'll update the app from the [Mobile Services Quick Start tutorial] to enable offline sync, and then test the app by adding data offline, syncing those items to the online database, and verifying the changes in the Azure classic portal.
Whether you are offline or connected, conflicts can arise any time multiple changes are made to data. A future tutorial will explore handling sync conflicts, where you choose which version of the changes to accept. In this tutorial, we assume no sync conflicts and any changes you make to existing data will be applied directly to the Azure SQL Server.
## What you need to get started
This tutorial is based on the code you download in the Mobile Services quickstart. Before you start this tutorial, you must first complete either [Get started with Mobile Services] or [Add Mobile Services to an existing app].
> [AZURE.IMPORTANT] If you completed the quickstart tutorial prior to the release of Azure Mobile Services Android SDK 2.0, you must re-do it, because the SDK is not backwards compatible. To verify the version, check the **dependencies** section of your project's **build.gradle** file.
## Update the app to support offline sync
With offline sync you read to and write from a *sync table* (using the *IMobileServiceSyncTable* interface), which is part of a **SQLite** database on your device.
To push and pull changes between the device and Azure Mobile Services, you use a *synchronization context* (*MobileServiceClient.SyncContext*), which you initialize with the local database that you use to store data locally.
1. Add permission to check for network connectivity by adding this code to the *AndroidManifest.xml* file:
2. Add the following **import** statements to *ToDoActivity.java*:
import java.util.Map;
import android.widget.Toast;
import com.microsoft.windowsazure.mobileservices.table.query.Query;
import com.microsoft.windowsazure.mobileservices.table.sync.MobileServiceSyncContext;
import com.microsoft.windowsazure.mobileservices.table.sync.MobileServiceSyncTable;
import com.microsoft.windowsazure.mobileservices.table.sync.localstore.ColumnDataType;
import com.microsoft.windowsazure.mobileservices.table.sync.localstore.SQLiteLocalStore;
3. Near the top of the `ToDoActivity` class, change the declaration of the `mToDoTable` variable from a `MobileServiceTable` class to a `MobileServiceSyncTable` class.
private MobileServiceSyncTable mToDoTable;
This is where you define the sync table.
4. To handle initialization of the local store, in the `onCreate` method, add the following lines after creating the `MobileServiceClient` instance:
// Saves the query which will be used for pulling data
mPullQuery = mClient.getTable(ToDoItem.class).where().field("complete").eq(false);
SQLiteLocalStore localStore = new SQLiteLocalStore(mClient.getContext(), "ToDoItem", null, 1);
SimpleSyncHandler handler = new SimpleSyncHandler();
MobileServiceSyncContext syncContext = mClient.getSyncContext();
Map tableDefinition = new HashMap();
tableDefinition.put("id", ColumnDataType.String);
tableDefinition.put("text", ColumnDataType.String);
tableDefinition.put("complete", ColumnDataType.Boolean);
tableDefinition.put("__version", ColumnDataType.String);
localStore.defineTable("ToDoItem", tableDefinition);
syncContext.initialize(localStore, handler).get();
// Get the Mobile Service Table instance to use
mToDoTable = mClient.getSyncTable(ToDoItem.class);
5. Following the preceding code, which is inside a `try` block, add an additional `catch` block following the `MalformedURLException` one:
} catch (Exception e) {
Throwable t = e;
while (t.getCause() != null) {
t = t.getCause();
}
createAndShowDialog(new Exception("Unknown error: " + t.getMessage()), "Error");
}
6. Add this method to verify network connectivity:
private boolean isNetworkAvailable() {
ConnectivityManager connectivityManager
= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
7. Add this method to sync between the local *SQL Light* store and the Azure SQL Server:
public void syncAsync(){
if (isNetworkAvailable()) {
new AsyncTask() {
@Override
protected Void doInBackground(Void... params) {
try {
mClient.getSyncContext().push().get();
mToDoTable.pull(mPullQuery).get();
} catch (Exception exception) {
createAndShowDialog(exception, "Error");
}
return null;
}
}.execute();
} else {
Toast.makeText(this, "You are not online, re-sync later!" +
"", Toast.LENGTH_LONG).show();
}
}
8. In the `onCreate` method, add this code as the next-to-the-last line, right before the call to `refreshItemsFromTable`:
syncAsync();
This causes the device on startup to sync with the Azure table. Otherwise you would display the last offline contents of the local store.
9. Update the code in the `refreshItemsFromTable` method to use this query (first line of code inside the `try` block):
final MobileServiceList result = mToDoTable.read(mPullQuery).get();
10. In the `onOptionsItemSelected` method replace the contents of the `if` block with this code:
syncAsync();
refreshItemsFromTable();
This code runs when you press the **Refresh** button in the upper right corner. This is the main way you sync your local store to Azure, in addition to syncing at startup. This encourages batching of sync changes, and is efficient given that the pull from Azure is a relatively expensive operation. You could also design this app to sync on every change by adding a call to `syncAsync` to the `addItem` and `checkItem` methods, if your app required this.
## Test the app
In this section, you will test the behavior with WiFi on, and then turn off WiFi to create an offline scenario.
When you add data items, they are held in the local SQL Light store, but not synced to the mobile service until you press the **Refresh** button. Other apps may have different requirements regarding when data needs to be synchronized, but for demo purposes this tutorial has the user explicitly request it.
When you press that button, a new background task starts, and first pushes all the changes made to the local store, by using the synchronization context, and then pulls all changed data from Azure to the local table.
### Online testing
Lets test the following scenarios.
1. Add some new items on your device;
2. Verify the items don't show in the portal;
3. next press **Refresh** and verify that they then show up.
4. Change or add an item in the portal, then press **Refresh** and verify that the changes show up on your device.
### Offline testing
1. Place the device or simulator in *Airplane Mode*. This creates an offline scenario.
2. Add some *ToDo* items, or mark some items as complete. Quit the device or simulator (or forcibly close the app) and restart. Verify that your changes have been persisted on the device because they are held in the local SQL Light store.
3. View the contents of the Azure *TodoItem* table. Verify that the new items have _not_ been synced to the server:
- For the JavaScript backend, go to the Azure classic portal, and click the Data tab to view the contents of the `TodoItem` table.
- For the .NET backend, view the table contents either with a SQL tool such as *SQL Server Management Studio*, or a REST client such as *Fiddler* or *Postman*.
4. Turn on WiFi in the device or simulator. Next, press the **Refresh** button.
5. View the TodoItem data again in the Azure classic portal. The new and changed TodoItems should now appear.
## Next Steps
* [Using Soft Delete in Mobile Services][Soft Delete]
## Additional Resources
* [Cloud Cover: Offline Sync in Azure Mobile Services]
* [Azure Friday: Offline-enabled apps in Azure Mobile Services] \(note: demos are for Windows, but feature discussion applies to all platforms\)
[Get the sample app]: #get-app
[Review the Core Data model]: #review-core-data
[Review the Mobile Services sync code]: #review-sync
[Change the sync behavior of the app]: #setup-sync
[Test the app]: #test-app
[Get started with Mobile Services]: mobile-services-android-get-started.md
[Add Mobile Services to an existing app]: mobile-services-android-get-started-data.md
[Mobile Services sample repository on GitHub]: https://github.com/Azure/mobile-services-samples
[Handling Conflicts with Offline Support for Mobile Services]: mobile-services-android-handling-conflicts-offline-data.md
[Soft Delete]: mobile-services-using-soft-delete.md
[Cloud Cover: Offline Sync in Azure Mobile Services]: http://channel9.msdn.com/Shows/Cloud+Cover/Episode-155-Offline-Storage-with-Donna-Malayeri
[Azure Friday: Offline-enabled apps in Azure Mobile Services]: http://azure.microsoft.com/documentation/videos/azure-mobile-services-offline-enabled-apps-with-donna-malayeri/
[Mobile Services Quick Start tutorial]: mobile-services-android-get-started.md
================================================
FILE: docs/mobile-services-android-get-started-users.md
================================================
# Add authentication to your Mobile Services Android app (JavaScript backend)
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-users.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started-users.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-users.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-get-started-users.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-windows-phone-get-started-users.md)
- [(Android | Javascript)](mobile-services-android-get-started-users.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started-users.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-users.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-users.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-users.md)
- [(HTML | Javascript)](mobile-services-html-get-started-users.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
## Summary
This topic shows you how to authenticate users in Azure Mobile Services from your app. In this tutorial, you add authentication to the quickstart project using an identity provider that is supported by Mobile Services. After being successfully authenticated and authorized by Mobile Services, the user ID value is displayed.
> [AZURE.VIDEO android-getting-started-with-authentication-in-windows-azure-mobile-services]
This tutorial walks you through the basic steps to enable authentication in your app.
## Prerequisites
This tutorial is based on the code you download in the Mobile Services quickstart. Before you start this tutorial, you must first complete either [Get started with Mobile Services] or [Add Mobile Services to an existing app].
> [AZURE.IMPORTANT] If you completed the quickstart tutorial prior to the release of Azure Mobile Services Android SDK 2.0, you must re-do it, because the SDK is not backwards compatible. To verify the version, check the **dependencies** section of your project's **build.gradle** file.
## Register your app for authentication and configure Mobile Services
1. In the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Dashboard**, and make a note of the **Mobile Service URL** value.
2. Register your app with one or more of the following authentication providers:
* [Google](./
mobile-services-how-to-register-google-authentication.md)
* [Facebook](./
mobile-services-how-to-register-facebook-authentication.md)
* [Twitter](./
mobile-services-how-to-register-twitter-authentication.md)
* [Microsoft](./
mobile-services-how-to-register-microsoft-authentication.md)
* [Azure Active Directory](./
mobile-services-how-to-register-active-directory-authentication.md).
Make a note of the client identity and client secret values generated by the provider. Do not distribute or share the client secret.
3. Back in the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Identity** > your identity provider settings, then enter the client ID and secret value from your provider.
You've now configured both your app and your mobile service to work with your auth provider. You may optionally repeat all these steps for each additional identity provider you'd like to support.
> [AZURE.IMPORTANT] Verify that you've set the correct redirect URI on your identity provider's developer site. As described in the linked instructions for each provider above, the redirect URI may be different for a .NET backend service vs. for a JavaScript backend service. An incorrectly configured redirect URI may result in the login screen not being displayed properly and the app malfunctioning in unexpected ways.
## Restrict permissions to authenticated users
To secure your endpoints, you must restrict access to only authenticated clients.
1. In the [Azure classic portal](https://manage.windowsazure.com/), navigate to your mobile service, then click **Data** > your table name (**TodoItem**) > **Permissions**.
2. Set all of the table operation permissions to **Only authenticated users**.
This ensures that all operations against the table require an authenticated user, which is required for this tutorial. You can set different permissions on each operations to support your specific scenario.
1. In Android Studio, open the project that you created when you completed the tutorial [Get started with Mobile Services].
2. From the **Run** menu, then click **Run app**; verify that an unhandled exception with a status code of 401 (Unauthorized) is raised after the app starts.
This happens because the app attempts to access Mobile Services as an unauthenticated user, but the _TodoItem_ table now requires authentication.
Next, you will update the app to authenticate users before requesting resources from the mobile service.
## Add authentication to the app
1. In **Project Explorer** in Android Studio, open the ToDoActivity.java file and add the following import statements.
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import com.microsoft.windowsazure.mobileservices.authentication.MobileServiceAuthenticationProvider;
import com.microsoft.windowsazure.mobileservices.authentication.MobileServiceUser;
2. Add the following method to the **ToDoActivity** class:
private void authenticate() {
// Login using the Google provider.
ListenableFuture mLogin = mClient.login(MobileServiceAuthenticationProvider.Google);
Futures.addCallback(mLogin, new FutureCallback() {
@Override
public void onFailure(Throwable exc) {
createAndShowDialog((Exception) exc, "Error");
}
@Override
public void onSuccess(MobileServiceUser user) {
createAndShowDialog(String.format(
"You are now logged in - %1$2s",
user.getUserId()), "Success");
createTable();
}
});
}
This creates a new method to handle the authentication process. The user is authenticated by using a Google login. A dialog is displayed which displays the ID of the authenticated user. You cannot proceed without a positive authentication.
> [AZURE.NOTE] If you are using an identity provider other than Google, change the value passed to the **login** method above to one of the following: _MicrosoftAccount_, _Facebook_, _Twitter_, or _windowsazureactivedirectory_.
3. In the **onCreate** method, add the following line of code after the code that instantiates the `MobileServiceClient` object.
authenticate();
This call starts the authentication process.
4. Move the remaining code after `authenticate();` in the **onCreate** method to a new **createTable** method, which looks like this:
private void createTable() {
// Get the table instance to use.
mToDoTable = mClient.getTable(ToDoItem.class);
mTextNewToDo = (EditText) findViewById(R.id.textNewToDo);
// Create an adapter to bind the items with the view.
mAdapter = new ToDoItemAdapter(this, R.layout.row_list_to_do);
ListView listViewToDo = (ListView) findViewById(R.id.listViewToDo);
listViewToDo.setAdapter(mAdapter);
// Load the items from Azure.
refreshItemsFromTable();
}
9. From the **Run** menu, then click **Run app** to start the app and sign in with your chosen identity provider.
When you are successfully logged-in, the app should run without errors, and you should be able to query the backend service and make updates to data.
## Cache authentication tokens on the client
The previous example showed a standard sign-in, which requires the client to contact both the identity provider and the backend Azure service every time that the app starts. Not only is this method inefficient, you can run into usage-related issues should many customers try to start you app at the same time. A better approach is to cache the authorization token returned by the Azure service and try to use this first before using a provider-based sign-in.
>[AZURE.NOTE]You can cache the token issued by the backend Azure service regardless of whether you are using client-managed or service-managed authentication. This tutorial uses service-managed authentication.
1. Open the ToDoActivity.java file and add the following import statements:
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
2. Add the the following members to the `ToDoActivity` class.
public static final String SHAREDPREFFILE = "temp";
public static final String USERIDPREF = "uid";
public static final String TOKENPREF = "tkn";
3. In the ToDoActivity.java file, add the the following definition for the `cacheUserToken` method.
private void cacheUserToken(MobileServiceUser user)
{
SharedPreferences prefs = getSharedPreferences(SHAREDPREFFILE, Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putString(USERIDPREF, user.getUserId());
editor.putString(TOKENPREF, user.getAuthenticationToken());
editor.commit();
}
This method stores the user id and token in a preference file that is marked private. This should protect access to the cache so that other apps on the device do not have access to the token because the preference is sandboxed for the app. However, if someone gains access to the device, it is possible that they may gain access to the token cache through other means.
>[AZURE.NOTE]You can further protect the token with encryption if token access to your data is considered highly sensitive and someone may gain access to the device. However, a completely secure solution is beyond the scope of this tutorial and dependent on your security requirements.
4. In the ToDoActivity.java file, add the the following definition for the `loadUserTokenCache` method.
private boolean loadUserTokenCache(MobileServiceClient client)
{
SharedPreferences prefs = getSharedPreferences(SHAREDPREFFILE, Context.MODE_PRIVATE);
String userId = prefs.getString(USERIDPREF, null);
if (userId == null)
return false;
String token = prefs.getString(TOKENPREF, null);
if (token == null)
return false;
MobileServiceUser user = new MobileServiceUser(userId);
user.setAuthenticationToken(token);
client.setCurrentUser(user);
return true;
}
5. In the *ToDoActivity.java* file, replace the `authenticate` method with the following method which uses a token cache. Change the login provider if you want to use an account other than Google.
private void authenticate() {
// We first try to load a token cache if one exists.
if (loadUserTokenCache(mClient))
{
createTable();
}
// If we failed to load a token cache, login and create a token cache
else
{
// Login using the Google provider.
ListenableFuture mLogin = mClient.login(MobileServiceAuthenticationProvider.Google);
Futures.addCallback(mLogin, new FutureCallback() {
@Override
public void onFailure(Throwable exc) {
createAndShowDialog("You must log in. Login Required", "Error");
}
@Override
public void onSuccess(MobileServiceUser user) {
createAndShowDialog(String.format(
"You are now logged in - %1$2s",
user.getUserId()), "Success");
cacheUserToken(mClient.getCurrentUser());
createTable();
}
});
}
}
6. Build the app and test authentication using a valid account. Run it at least twice. During the first run, you should receive a prompt to login and create the token cache. After that, each run will attempt to load the token cache for authentication and you should not be required to login.
## Refresh the token cache
Our token cache should work in a simple case but, what happens when the token expires or is revoked? The token could expire when the app is not running. This would mean the token cache is invalid. The token could also expire while the app is actually running. The result is an HTTP status code 401 "Unauthorized".
We need to be able to detect an expired token, and refresh it. To do this we use a [ServiceFilter](http://dl.windowsazure.com/androiddocs/com/microsoft/windowsazure/mobileservices/ServiceFilter.html) from the [Android client library](http://dl.windowsazure.com/androiddocs/).
In this section you will define a ServiceFilter that will detect a HTTP status code 401 response and trigger a refresh of the token and the token cache. Additionally, this ServiceFilter will block other outbound requests during authentication so that those requests can use the refreshed token.
1. Open the ToDoActivity.java file and add the following import statements:
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.ExecutionException;
import com.microsoft.windowsazure.mobileservices.MobileServiceException;
2. Add the following members to the `ToDoActivity` class.
public boolean bAuthenticating = false;
public final Object mAuthenticationLock = new Object();
These will be used to help synchronize the authentication of the user. We only want to authenticate once. Any calls during an authentication should wait and use the new token from the authentication in progress.
3. In the ToDoActivity.java file, add the following method to the ToDoActivity class that will be used to block outbound calls on other threads while authentication is in progress.
/**
* Detects if authentication is in progress and waits for it to complete.
* Returns true if authentication was detected as in progress. False otherwise.
*/
public boolean detectAndWaitForAuthentication()
{
boolean detected = false;
synchronized(mAuthenticationLock)
{
do
{
if (bAuthenticating == true)
detected = true;
try
{
mAuthenticationLock.wait(1000);
}
catch(InterruptedException e)
{}
}
while(bAuthenticating == true);
}
if (bAuthenticating == true)
return true;
return detected;
}
4. In the ToDoActivity.java file, add the following method to the ToDoActivity class. This method triggers the wait and then update the token on outbound requests when authentication is complete.
/**
* Waits for authentication to complete then adds or updates the token
* in the X-ZUMO-AUTH request header.
*
* @param request
* The request that receives the updated token.
*/
private void waitAndUpdateRequestToken(ServiceFilterRequest request)
{
MobileServiceUser user = null;
if (detectAndWaitForAuthentication())
{
user = mClient.getCurrentUser();
if (user != null)
{
request.removeHeader("X-ZUMO-AUTH");
request.addHeader("X-ZUMO-AUTH", user.getAuthenticationToken());
}
}
}
5. In the ToDoActivity.java file, update the `authenticate` method of the ToDoActivity class so that it accepts a boolean parameter to allow forcing the refresh of the token and token cache. We also need to notify any blocked threads when authentication is completed so they can pick up the new token.
/**
* Authenticates with the desired login provider. Also caches the token.
*
* If a local token cache is detected, the token cache is used instead of an actual
* login unless bRefresh is set to true forcing a refresh.
*
* @param bRefreshCache
* Indicates whether to force a token refresh.
*/
private void authenticate(boolean bRefreshCache) {
bAuthenticating = true;
if (bRefreshCache || !loadUserTokenCache(mClient))
{
// New login using the provider and update the token cache.
mClient.login(MobileServiceAuthenticationProvider.MicrosoftAccount,
new UserAuthenticationCallback() {
@Override
public void onCompleted(MobileServiceUser user,
Exception exception, ServiceFilterResponse response) {
synchronized(mAuthenticationLock)
{
if (exception == null) {
cacheUserToken(mClient.getCurrentUser());
createTable();
} else {
createAndShowDialog(exception.getMessage(), "Login Error");
}
bAuthenticating = false;
mAuthenticationLock.notifyAll();
}
}
});
}
else
{
// Other threads may be blocked waiting to be notified when
// authentication is complete.
synchronized(mAuthenticationLock)
{
bAuthenticating = false;
mAuthenticationLock.notifyAll();
}
createTable();
}
}
6. In the ToDoActivity.java file, add this code for a new `RefreshTokenCacheFilter` class inside the ToDoActivity class:
/**
* The RefreshTokenCacheFilter class filters responses for HTTP status code 401.
* When 401 is encountered, the filter calls the authenticate method on the
* UI thread. Out going requests and retries are blocked during authentication.
* Once authentication is complete, the token cache is updated and
* any blocked request will receive the X-ZUMO-AUTH header added or updated to
* that request.
*/
private class RefreshTokenCacheFilter implements ServiceFilter {
AtomicBoolean mAtomicAuthenticatingFlag = new AtomicBoolean();
@Override
public ListenableFuture handleRequest(
final ServiceFilterRequest request,
final NextServiceFilterCallback nextServiceFilterCallback
)
{
// In this example, if authentication is already in progress we block the request
// until authentication is complete to avoid unnecessary authentications as
// a result of HTTP status code 401.
// If authentication was detected, add the token to the request.
waitAndUpdateRequestToken(request);
// Send the request down the filter chain
// retrying up to 5 times on 401 response codes.
ListenableFuture future = null;
ServiceFilterResponse response = null;
int responseCode = 401;
for (int i = 0; (i < 5 ) && (responseCode == 401); i++)
{
future = nextServiceFilterCallback.onNext(request);
try {
response = future.get();
responseCode = response.getStatus().getStatusCode();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
if (e.getCause().getClass() == MobileServiceException.class)
{
MobileServiceException mEx = (MobileServiceException) e.getCause();
responseCode = mEx.getResponse().getStatus().getStatusCode();
if (responseCode == 401)
{
// Two simultaneous requests from independent threads could get HTTP status 401.
// Protecting against that right here so multiple authentication requests are
// not setup to run on the UI thread.
// We only want to authenticate once. Requests should just wait and retry
// with the new token.
if (mAtomicAuthenticatingFlag.compareAndSet(false, true))
{
// Authenticate on UI thread
runOnUiThread(new Runnable() {
@Override
public void run() {
// Force a token refresh during authentication.
authenticate(true);
}
});
}
// Wait for authentication to complete then update the token in the request.
waitAndUpdateRequestToken(request);
mAtomicAuthenticatingFlag.set(false);
}
}
}
}
return future;
}
}
This service filter will check each response for HTTP status code 401 "Unauthorized". If a 401 is encountered, a new login request to obtain a new token will be setup on the UI thread. Other calls will be blocked until the login is completed, or until 5 attempts have failed. If the new token is obtained, the request that triggered the 401 will be retried with the new token and any blocked calls will be retried with the new token.
7. In the ToDoActivity.java file, add this code for a new `ProgressFilter` class inside the ToDoActivity class:
/**
* The ProgressFilter class renders a progress bar on the screen during the time the App is waiting for the response of a previous request.
* the filter shows the progress bar on the beginning of the request, and hides it when the response arrived.
*/
private class ProgressFilter implements ServiceFilter {
@Override
public ListenableFuture handleRequest(ServiceFilterRequest request, NextServiceFilterCallback nextServiceFilterCallback) {
final SettableFuture resultFuture = SettableFuture.create();
runOnUiThread(new Runnable() {
@Override
public void run() {
if (mProgressBar != null) mProgressBar.setVisibility(ProgressBar.VISIBLE);
}
});
ListenableFuture future = nextServiceFilterCallback.onNext(request);
Futures.addCallback(future, new FutureCallback() {
@Override
public void onFailure(Throwable e) {
resultFuture.setException(e);
}
@Override
public void onSuccess(ServiceFilterResponse response) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (mProgressBar != null) mProgressBar.setVisibility(ProgressBar.GONE);
}
});
resultFuture.set(response);
}
});
return resultFuture;
}
}
This filter will show the progress bar on the beginning of the request and will hide it when the response arrived.
8. In the ToDoActivity.java file, update the `onCreate` method as follows:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_to_do);
mProgressBar = (ProgressBar) findViewById(R.id.loadingProgressBar);
// Initialize the progress bar
mProgressBar.setVisibility(ProgressBar.GONE);
try {
// Create the Mobile Service Client instance, using the provided
// Mobile Service URL and key
mClient = new MobileServiceClient(
"https://.azure-mobile.net/",
"", this)
.withFilter(new ProgressFilter())
.withFilter(new RefreshTokenCacheFilter());
// Authenticate passing false to load the current token cache if available.
authenticate(false);
} catch (MalformedURLException e) {
createAndShowDialog(new Exception("Error creating the Mobile Service. " +
"Verify the URL"), "Error");
}
}
In this code, `RefreshTokenCacheFilter` is used in addition to `ProgressFilter`. Also during `onCreate` we want to load the token cache. So `false` is passed in to the `authenticate` method.
## Next steps
In the next tutorial, [Authorize users with scripts], you will take the user ID value provided by Mobile Services based on an authenticated user and use it to filter the data returned by Mobile Services.
[Register your app for authentication and configure Mobile Services]: #register
[Restrict table permissions to authenticated users]: #permissions
[Add authentication to the app]: #add-authentication
[Store authentication tokens on the client]: #cache-tokens
[Refresh expired tokens]: #refresh-tokens
[Next Steps]:#next-steps
[4]: ./media/mobile-services-android-get-started-users/mobile-services-selection.png
[5]: ./media/mobile-services-android-get-started-users/mobile-service-uri.png
[13]: ./media/mobile-services-android-get-started-users/mobile-identity-tab.png
[14]: ./media/mobile-services-android-get-started-users/mobile-portal-data-tables.png
[15]: ./media/mobile-services-android-get-started-users/mobile-portal-change-table-perms.png
[Submit an app page]: http://go.microsoft.com/fwlink/p/?LinkID=266582
[My Applications]: http://go.microsoft.com/fwlink/p/?LinkId=262039
[Live SDK for Windows]: http://go.microsoft.com/fwlink/p/?LinkId=262253
[Get started with Mobile Services]: mobile-services-android-get-started.md
[Authorize users with scripts]: mobile-services-javascript-backend-service-side-authorization.md
================================================
FILE: docs/mobile-services-android-get-started.md
================================================
# Get started with Mobile Services for Android (JavaScript backend)
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal JavaScript | Javascript)](mobile-services-javascript-backend-windows-store-javascript-get-started.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started.md)
- [(Android | Javascript)](mobile-services-android-get-started.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started.md)
- [(HTML | Javascript)](mobile-services-html-get-started.md)
- [(PhoneGap | Javascript)](mobile-services-javascript-backend-phonegap-get-started.md)
- [(Sencha | Javascript)](partner-sencha-mobile-services-get-started.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This tutorial shows you how to add a cloud-based backend service to an Android app using Azure Mobile Services. In this tutorial, you will create both a new mobile service and a simple **To do list** app that stores app data in the new mobile service.
> [AZURE.VIDEO mobile-get-started-android]
A screenshot from the completed app is below:

## Prerequisites
Completing this tutorial requires the [Android Developer Tools](https://developer.android.com/sdk/index.html), which includes the Android Studio integrated development environment, and the latest Android platform. Android 4.2 or a later version is required.
The downloaded quickstart project contains the Azure Mobile Services SDK for Android.
> [AZURE.IMPORTANT] To complete this tutorial, you need an Azure account. If you don't have an account, you can create a free trial account in just a couple of minutes. For details, see [Azure Free Trial](https://azure.microsoft.com/pricing/free-trial/?WT.mc_id=AE564AB28).
## Create a new mobile service
Follow these steps to create a new mobile service.
1. Log into the [Azure classic portal](https://manage.windowsazure.com/). At the bottom of the navigation pane, click **+NEW**. Expand **Compute** and **Mobile Service**, then click **Create**.

This displays the **Create a Mobile Service** dialog.
2. In the **Create a Mobile Service** dialog, select **Create a free 20 MB SQL Database**, select **JavaScript** runtime, then type a subdomain name for the new mobile service in the **URL** textbox. Click the right arrow button to go to the next page.

This displays the **Specify database settings** page.
>[AZURE.NOTE]As part of this tutorial, you create a new SQL Database instance and server. You can reuse this new database and administer it as you would any other SQL Database instance. If you already have a database in the same region as the new mobile service, you can instead choose **Use existing Database** and then select that database. The use of a database in a different region is not recommended because of additional bandwidth costs and higher latencies.
3. In **Name**, type the name of the new database, then type **Login name**, which is the administrator login name for the new SQL Database server, type and confirm the password, and click the check button to complete the process.

You have now created a new mobile service that can be used by your mobile apps.
## Create a new Android app
Once you have created your mobile service, you can follow an easy quickstart in the Azure classic portal to either create a new app or modify an existing app to connect to your mobile service.
In this section you will create a new Android app that is connected to your mobile service.
1. In the Azure classic portal, click **Mobile Services**, and then click the mobile service that you just created.
2. In the quickstart tab, click **Android** under **Choose platform** and expand **Create a new Android app**.

This displays the three easy steps to create an Android app connected to your mobile service.

3. If you haven't already done so, download and install the [Android Developer Tools](https://go.microsoft.com/fwLink/p/?LinkID=280125) on your local computer or virtual machine.
4. Click **Create TodoItem table** to create a table to store app data.
5. Now download your app by pressing the **Download** button.
## Run your Android app
The final stage of this tutorial is to build and run your new app.
### Load project into Android Studio and sync Gradle
1. Browse to the location where you saved the compressed project files and expand the files on your computer into your Android Studio projects directory.
2. Open Android Studio. If you are working with a project and it appears, close the project (File => Close Project).
3. Select **Open an existing Android Studio project**, browse to the project location, and then click **OK.** This will load the project and start to sync it with Gradle.

4. Wait for the Gradle sync activity to complete. If you see a "failed to find target" error, this is because the version used in Android Studio doesn't match that of the sample. The easiest way to fix this is to click the **Install missing platform(s) and sync project** link in the error message. You might get additional version error messages, and you simply repeat this process until no errors appear.
- There is another way to fix this if you want to run with the "latest and greatest" version of Android. You can update the **targetSdkVersion** in the *build.gradle* file in the *app* directory to match the version already installed on your machine, which you can discover by clicking the **SDK Manager** icon and seeing what version is listed. Next you press the **Sync Project with Gradle Files**. You may get an error message for the version of Build Tools, and you fix that the same way.
### Running the app
You can run the app using the emulator, or using an actual device.
1. To run from a device, connect it to your computer with a USB cable. You must [set up the device for development](https://developer.android.com/training/basics/firstapp/running-app.html). If you are developing on a Windows machine, you must also download and install a USB driver.
2. To run using the Android emulator, you must define at least one Android Virtual Device (AVD). Click the AVD Manager icon to create and manage these devices.
3. From the **Run** menu, click **Run** to start the project. and choose a device or emulator from the dialog box that appears.
4. When the app appears, type meaningful text, such as _Complete the tutorial_, and then click **Add**.

This sends a POST request to the new mobile service hosted in Azure. Data from the request is inserted into the TodoItem table. Items stored in the table are returned by the mobile service, and the data is displayed in the list.
> [AZURE.NOTE] You can review the code that accesses your mobile service to query and insert data, which is found in the ToDoActivity.java file.
8. Back in the Azure classic portal, click the **Data** tab and then click the **TodoItems** table.

This lets you browse the data inserted by the app into the table.

## Next Steps
Now that you have completed the quickstart, learn how to perform additional important tasks in Mobile Services:
* [Get started with data]
Learn more about storing and querying data using Mobile Services.
* [Get started with authentication]
Learn how to authenticate users of your app with an identity provider.
* [Get started with push notifications]
Learn how to send a very basic push notification to your app.
[Get started (Eclipse)]: mobile-services-android-get-started-ec.md
[Get started with data]: mobile-services-android-get-started-data.md
[Get started with authentication]: mobile-services-android-get-started-users.md
[Get started with push notifications]: mobile-services-javascript-backend-android-get-started-push.md
[Mobile Services Android SDK]: https://go.microsoft.com/fwLink/p/?LinkID=266533
================================================
FILE: docs/mobile-services-android-how-to-use-client-library.md
================================================
# How to use the Android client library for Mobile Services
> [AZURE.SELECTOR]
- [Android](mobile-services-android-how-to-use-client-library.md)
- [HTML/JavaScript](mobile-services-html-how-to-use-client-library.md)
- [iOS](mobile-services-ios-how-to-use-client-library.md)
- [Managed (Windows/Xamarin)](mobile-services-dotnet-how-to-use-client-library.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This guide shows you how to perform common scenarios using the Android client for Azure Mobile Services. The scenarios covered include querying for data; inserting, updating, and deleting data, authenticating users, handling errors, and customizing the client.
If you are new to Mobile Services, you should first complete the quickstart tutorial [Get started with Mobile Services]. Successfully completing that tutorial ensures that you will have installed Android Studio; it will help you configure your account and create your first mobile service, and install the Mobile Services SDK, which supports Android version 2.2 or later, but we recommend building against Android version 4.2 or later.
You can find the Javadocs API reference for the Android client library [here](http://go.microsoft.com/fwlink/p/?LinkId=298735).
## What is Mobile Services
Azure Mobile Services is a highly scalable mobile application development platform that lets you add enhanced functionality to your mobile device apps by using Azure.
With Mobile Services you can:
+ **Build native and cross platform apps** - Connect your iOS, Android, Windows, or cross-platform Xamarin or Cordova (Phonegap) apps to your backend mobile service using native SDKs.
+ **Send push notifications to your users** - Send push notifications to your users of your app.
+ **Authenticate your users** - Leverage popular identity providers like Facebook and Twitter to authenticate your app users.
+ **Store data in the cloud** - Store user data in a SQL Database (by default) or in Mongo DB, DocumentDB, Azure Tables, or Azure Blobs.
+ **Build offline-ready apps with sync** - Make your apps work offline and use Mobile Services to sync data in the background.
+ **Monitor and scale your apps** - Monitor app usage and scale your backend as demand grows.
## Mobile Services Concepts
The following are important features and concepts in the Mobile Services:
+ **Application key:** a unique value that is used to limit access to your mobile service from random clients; this "key" is not a security token and is not used to authenticate users of your app.
+ **Backend:** the mobile service instance that supports your app. A mobile service is implemented either as an ASP.NET Web API project (*.NET backend* ) or as a Node.js project (*JavaScript backend*).
+ **Identity provider:** an external service, trusted by Mobile Services, that authenticates your app's users. Supported providers include: Facebook, Twitter, Google, Microsoft Account, and Azure Active Directory.
+ **Push notification:** Service-initiated message that is sent to a registered device or user using Azure Notification Hubs.
+ **Scale:** The ability to add, for an additional cost, more processing power, performance, and storage as your app becomes more popular.
+ **Scheduled job:** Custom code that is run either on a pre-determined schedule or on-demand.
For more information, see [Mobile Services Concepts](./
mobile-services-concepts-links.md).
## Setup and Prerequisites
We assume that you have created a mobile service and a table. For more information see [Create a table](http://go.microsoft.com/fwlink/p/?LinkId=298592). In the code used in this topic, we assume the table is named *ToDoItem*, and that it has the following columns:
- id
- text
- complete
The corresponding typed client side object is the following:
public class ToDoItem {
private String id;
private String text;
private Boolean complete;
}
When dynamic schema is enabled, Azure Mobile Services automatically generates new columns based on the object in the insert or update request. For more information, see [Dynamic schema](http://go.microsoft.com/fwlink/p/?LinkId=296271).
## How to: Create the Mobile Services client
The following code creates the [MobileServiceClient](http://dl.windowsazure.com/androiddocs/com/microsoft/windowsazure/mobileservices/MobileServiceClient.html) object that is used to access your mobile service. The code goes in the `onCreate` method of the Activity class specified in *AndroidManifest.xml* as a **MAIN** action and **LAUNCHER** category.
MobileServiceClient mClient = new MobileServiceClient(
"MobileServiceUrl", // Replace with the above Site URL
"AppKey", // replace with the Application Key
this)
In the code above, replace `MobileServiceUrl` and `AppKey` with the mobile service URL and application key, in that order. Both of these are available on the Azure classic portal, by selecting your mobile service and then clicking on *Dashboard*.
## How to: Create a table reference
The easiest way to query or modify data in the mobile service is by using the *typed programming model*, since Java is a strongly typed language (later on we will discuss the *untyped* model). This model provides seamless serialization and deserialization to JSON using the [gson](http://go.microsoft.com/fwlink/p/?LinkId=290801) library when sending data between the client and the mobile service: the developer doesn't have to do anything, the framework handles it all.
The first thing you do to query or modify data is to create a [MobileServiceTable](http://go.microsoft.com/fwlink/p/?LinkId=296835) object by calling the **getTable** method on the [**MobileServiceClient**](http://dl.windowsazure.com/androiddocs/com/microsoft/windowsazure/mobileservices/MobileServiceClient.html). We will look at two overloads of this method:
public class MobileServiceClient {
public MobileServiceTable getTable(Class clazz);
public MobileServiceTable getTable(String name, Class clazz);
}
In the following code, *mClient* is a reference to your mobile service client.
The [first overload](http://go.microsoft.com/fwlink/p/?LinkId=296839) is used where the class name and the table name are the same:
MobileServiceTable mToDoTable = mClient.getTable(ToDoItem.class);
The [2nd overload](http://go.microsoft.com/fwlink/p/?LinkId=296840) is used when the table name is different from the type name.
MobileServiceTable mToDoTable = mClient.getTable("ToDoItemBackup", ToDoItem.class);
## The API structure
Since version 2.0 of the client library, mobile services table operations use the [Future](http://developer.android.com/reference/java/util/concurrent/Future.html) and [AsyncTask](http://developer.android.com/reference/android/os/AsyncTask.html) objects in all of the asynchronous operations such as methods involving queries and operations like inserts, updates and deletes. This makes it easier to perform multiple operations (while on a background thread) without having to deal with multiple nested callbacks.
## How to: Query data from a mobile service
This section describes how to issue queries to the mobile service. Subsections describe diffent aspects such as sorting, filtering, and paging. Finally, we discuss how you can concatenate these operations together.
### How to: Return all Items from a Table
The following code returns all items in the *ToDoItem* table. It displays them in the UI by adding the items to an adapter. This code is similar to what is in the the quickstart tutorial [Get started with Mobile Services].
new AsyncTask() {
@Override
protected Void doInBackground(Void... params) {
try {
final MobileServiceList result = mToDoTable.execute().get();
runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.clear();
for (ToDoItem item : result) {
mAdapter.add(item);
}
}
});
} catch (Exception exception) {
createAndShowDialog(exception, "Error");
}
return result;
}
}.execute();
Queries like this one use the [AsyncTask](http://developer.android.com/reference/android/os/AsyncTask.html) object.
The *result* variable returns the result set from the query, and the code following the `mToDoTable.execute().get()` statement shows how to display the individual rows.
### How to: Filter returned data
The following code returns all items from the *ToDoItem* table whose *complete* field equals *false*. *mToDoTable* is the reference to the mobile service table that we created previously.
new AsyncTask() {
@Override
protected Void doInBackground(Void... params) {
try {
final MobileServiceList result =
mToDoTable.where().field("complete").eq(false).execute().get();
for (ToDoItem item : result) {
Log.i(TAG, "Read object with ID " + item.id);
}
} catch (Exception exception) {
createAndShowDialog(exception, "Error");
}
return null;
}
}.execute();
You start a filter with a [**where**](http://go.microsoft.com/fwlink/p/?LinkId=296867) method call on the table reference. This is followed by a [**field**](http://go.microsoft.com/fwlink/p/?LinkId=296869) method call followed by a method call that specifies the logical predicate. Possible predicate methods include [**eq**](http://go.microsoft.com/fwlink/p/?LinkId=298461), [**ne**](http://go.microsoft.com/fwlink/p/?LinkId=298462), [**gt**](http://go.microsoft.com/fwlink/p/?LinkId=298463), [**ge**](http://go.microsoft.com/fwlink/p/?LinkId=298464), [**lt**](http://go.microsoft.com/fwlink/p/?LinkId=298465), [**le**](http://go.microsoft.com/fwlink/p/?LinkId=298466) etc.
This is sufficient for comparing number and string fields to specific values. But you can do a lot more.
For example, you can filter on dates. You can compare the entire date field, but you can also compare parts of the date, with methods such as [**year**](http://go.microsoft.com/fwlink/p/?LinkId=298467), [**month**](http://go.microsoft.com/fwlink/p/?LinkId=298468), [**day**](http://go.microsoft.com/fwlink/p/?LinkId=298469), [**hour**](http://go.microsoft.com/fwlink/p/?LinkId=298470), [**minute**](http://go.microsoft.com/fwlink/p/?LinkId=298471) and [**second**](http://go.microsoft.com/fwlink/p/?LinkId=298472). The following partial code adds a filter for items whose *due date* equals 2013.
mToDoTable.where().year("due").eq(2013).execute().get();
You can do a wide variety of complex filters on string fields with methods like [**startsWith**](http://go.microsoft.com/fwlink/p/?LinkId=298473), [**endsWith**](http://go.microsoft.com/fwlink/p/?LinkId=298474), [**concat**](http://go.microsoft.com/fwlink/p/?LinkId=298475), [**subString**](http://go.microsoft.com/fwlink/p/?LinkId=298477), [**indexOf**](http://go.microsoft.com/fwlink/p/?LinkId=298488), [**replace**](http://go.microsoft.com/fwlink/p/?LinkId=298491), [**toLower**](http://go.microsoft.com/fwlink/p/?LinkId=298492), [**toUpper**](http://go.microsoft.com/fwlink/p/?LinkId=298493), [**trim**](http://go.microsoft.com/fwlink/p/?LinkId=298495), and [**length**](http://go.microsoft.com/fwlink/p/?LinkId=298496). The following partial code filters for table rows where the *text* column starts with "PRI0".
mToDoTable.where().startsWith("text", "PRI0").execute().get();
Number fields also allow a wide variety of more complex filters with methods like [**add**](http://go.microsoft.com/fwlink/p/?LinkId=298497), [**sub**](http://go.microsoft.com/fwlink/p/?LinkId=298499), [**mul**](http://go.microsoft.com/fwlink/p/?LinkId=298500), [**div**](http://go.microsoft.com/fwlink/p/?LinkId=298502), [**mod**](http://go.microsoft.com/fwlink/p/?LinkId=298503), [**floor**](http://go.microsoft.com/fwlink/p/?LinkId=298505), [**ceiling**](http://go.microsoft.com/fwlink/p/?LinkId=298506), and [**round**](http://go.microsoft.com/fwlink/p/?LinkId=298507). The following partial code filters for table rows where the *duration* is an even number.
mToDoTable.where().field("duration").mod(2).eq(0).execute().get();
You can combine predicates with methods like [**and**](http://go.microsoft.com/fwlink/p/?LinkId=298512), [**or**](http://go.microsoft.com/fwlink/p/?LinkId=298514) and [**not**](http://go.microsoft.com/fwlink/p/?LinkId=298515). This partial code combines two of the above examples.
mToDoTable.where().year("due").eq(2013).and().startsWith("text", "PRI0")
.execute().get();
And you can group and nest logical operators, as shown in this partial code:
mToDoTable.where()
.year("due").eq(2013)
.and
(startsWith("text", "PRI0").or().field("duration").gt(10))
.execute().get();
For more detailed discussion and examples of filtering, see [Exploring the richness of the Mobile Services Android client query model](http://hashtagfail.com/post/46493261719/mobile-services-android-querying).
### How to: Sort returned data
The following code returns all items from a table of *ToDoItems* sorted ascending by the *text* field. *mToDoTable* is the reference to the mobile mervice table that you created previously.
mToDoTable.orderBy("text", QueryOrder.Ascending).execute().get();
The first parameter of the [**orderBy**](http://go.microsoft.com/fwlink/p/?LinkId=298519) method is a string equal to the name of the field on which to sort.
The second parameter uses the [**QueryOrder**](http://go.microsoft.com/fwlink/p/?LinkId=298521) enumeration to specify whether to sort ascending or descending.
Note that if you are filtering using the ***where*** method, the ***where*** method must be invoked prior to the ***orderBy*** method.
### How to: Return data in pages
The first example shows how to select the top 5 items from a table. The query returns the items from a table of *ToDoItems*. *mToDoTable* is the reference to the mobile service table that you created previously.
final MobileServiceList result = mToDoTable.top(5).execute().get();
Next, we define a query that skips the first 5 items, and then returns the next 5.
mToDoTable.skip(5).top(5).execute().get();
### How to: Select specific columns
The following code illustrates how to return all items from a table of *ToDoItems*, but only displays the *complete* and *text* fields. *mToDoTable* is the reference to the mobile service table that we created previously.
mToDoTable.select("complete", "text").execute().get();
Here the parameters to the select function are the string names of the table's columns that you want to return.
The [**select**](http://go.microsoft.com/fwlink/p/?LinkId=290689) method needs to follow methods like [**where**](http://go.microsoft.com/fwlink/p/?LinkId=296296) and [**orderBy**](http://go.microsoft.com/fwlink/p/?LinkId=296313), if they are present. It can be followed by methods like [**top**](http://go.microsoft.com/fwlink/p/?LinkId=298731).
### How to: Concatenate query methods
The methods used in querying mobile mervice tables can be concatenated. This allows you to do things like select specific columns of filtered rows that are sorted and paged. You can create quite complex logical filters.
What makes this work is that the query methods you use return [**MobileServiceQuery<T>**](http://go.microsoft.com/fwlink/p/?LinkId=298551) objects, which can in turn have additional methods invoked on them. To end the series of methods and actually run the query, you call the [**execute**](http://go.microsoft.com/fwlink/p/?LinkId=298554) method.
Here's a code sample where *mToDoTable* is a reference to the mobile services *ToDoItem* table.
mToDoTable.where().year("due").eq(2013)
.and().startsWith("text", "PRI0")
.or().field("duration").gt(10)
.select("id", "complete", "text", "duration")
.orderBy(duration, QueryOrder.Ascending).top(20)
.execute().get();
The main requirement in chaining methods together is that the *where* method and predicates need to come first. After that, you can call subsequent methods in the order that best meets the needs of your application.
## How to: Insert data into a mobile service
The following code shows how to insert a new row into a table.
First you instantiate an instance of the *ToDoItem* class and set its properties.
ToDoItem mToDoItem = new ToDoItem();
mToDoItem.text = "Test Program";
mToDoItem.complete = false;
Next you execute the following code:
// Insert the new item
new AsyncTask() {
@Override
protected Void doInBackground(Void... params) {
try {
mToDoTable.insert(item).get();
if (!item.isComplete()) {
runOnUiThread(new Runnable() {
public void run() {
mAdapter.add(item);
}
});
}
} catch (Exception exception) {
createAndShowDialog(exception, "Error");
}
return null;
}
}.execute();
This code inserts the new item, and adds it to the adapter so it displays in the UI.
Mobile Services supports unique custom string values for the table id. This allows applications to use custom values such as email addresses or usernames for the id column of a Mobile Services table. For example if you wanted to identify each record by an email address, you could use the following JSON object.
ToDoItem mToDoItem = new ToDoItem();
mToDoItem.id = "myemail@mydomain.com";
mToDoItem.text = "Test Program";
mToDoItem.complete = false;
If a string id value is not provided when inserting new records into a table, Mobile Services will generate a unique value for the id.
Supporting string ids provides the following advantages to developers
+ Ids can be generated without making a roundtrip to the database.
+ Records are easier to merge from different tables or databases.
+ Ids values can integrate better with an application's logic.
You can also use server scripts to set id values. The script example below generates a custom GUID and assigns it to a new record's id. This is similar to the id value that Mobile Services would generate if you didn't pass in a value for a record's id.
//Example of generating an id. This is not required since Mobile Services
//will generate an id if one is not passed in.
item.id = item.id || newGuid();
request.execute();
function newGuid() {
var pad4 = function(str) { return "0000".substring(str.length) + str; };
var hex4 = function () { return pad4(Math.floor(Math.random() * 0x10000 /* 65536 */ ).toString(16)); };
return (hex4() + hex4() + "-" + hex4() + "-" + hex4() + "-" + hex4() + "-" + hex4() + hex4() + hex4());
}
If an application provides a value for an id, Mobile Services will store it as is. This includes leading or trailing white spaces. White space will not be trimmed from value.
The value for the `id` must be unique and it must not include characters from the following sets:
+ Control characters: [0x0000-0x001F] and [0x007F-0x009F]. For more information, see [ASCII control codes C0 and C1].
+ Printable characters: **"**(0x0022), **\+** (0x002B), **/** (0x002F), **?** (0x003F), **\\** (0x005C), **`** (0x0060)
+ The ids "." and ".."
You can alternatively use integer Ids for your tables. In order to use an integer Id you must create your table with the `mobile table create` command using the `--integerId` option. This command is used with the Command-line Interface (CLI) for Azure. For more information on using the CLI, see [CLI to manage Mobile Services tables].
## How to: Update data in a mobile service
The following code shows how to update data in a table. In this example, *item* is a reference to a row in the *ToDoItem* table, which has had some changes made to it. The following method updates the table and the UI adapter.
private void updateItem(final ToDoItem item) {
if (mClient == null) {
return;
}
new AsyncTask() {
@Override
protected Void doInBackground(Void... params) {
try {
mToDoTable.update(item).get();
runOnUiThread(new Runnable() {
public void run() {
if (item.isComplete()) {
mAdapter.remove(item);
}
refreshItemsFromTable();
}
});
} catch (Exception exception) {
createAndShowDialog(exception, "Error");
}
return null;
}
}.execute();
}
## How to: Delete data in a mobile service
The following code shows how to delete data from a table. It deletes an existing item from the ToDoItem table that has had the **Completed** check box on the UI checked.
public void checkItem(final ToDoItem item) {
if (mClient == null) {
return;
}
// Set the item as completed and update it in the table
item.setComplete(true);
new AsyncTask() {
@Override
protected Void doInBackground(Void... params) {
try {
mToDoTable.delete(item);
runOnUiThread(new Runnable() {
public void run() {
if (item.isComplete()) {
mAdapter.remove(item);
}
refreshItemsFromTable();
}
});
} catch (Exception exception) {
createAndShowDialog(exception, "Error");
}
return null;
}
}.execute();
}
The following code illustrates another way to do this. It deletes an existing item in the ToDoItem table by specifying the value of the id field of the row to delete (assumed to equal "2FA404AB-E458-44CD-BC1B-3BC847EF0902"). In an actual app you would pick up the ID somehow and pass it in as a variable. Here, to simplify testing, you can go to your service in the Azure classic portal, click **Data** and copy an ID that you wish to test with.
public void deleteItem(View view) {
final String ID = "2FA404AB-E458-44CD-BC1B-3BC847EF0902";
new AsyncTask() {
@Override
protected Void doInBackground(Void... params) {
try {
mToDoTable.delete(ID);
runOnUiThread(new Runnable() {
public void run() {
refreshItemsFromTable();
}
});
} catch (Exception exception) {
createAndShowDialog(exception, "Error");
}
return null;
}
}.execute();
}
## How to: Look up a specific item
Sometimes you want to look up a specific item by its *id*, unlike querying where you typically get a collection of items that satisfy some criteria. The following code shows how to do this, for an *id* value of `0380BAFB-BCFF-443C-B7D5-30199F730335`. In an actual app you would pick up the ID somehow and pass it in as a variable. Here, to simplify testing, you can go to your service in the Azure classic portal, click the **Data** tab and copy an ID that you wish to test with.
/**
* Lookup specific item from table and UI
*/
public void lookup(View view) {
final String ID = "0380BAFB-BCFF-443C-B7D5-30199F730335";
new AsyncTask() {
@Override
protected Void doInBackground(Void... params) {
try {
final ToDoItem result = mToDoTable.lookUp(ID).get();
runOnUiThread(new Runnable() {
public void run() {
mAdapter.clear();
mAdapter.add(result);
}
});
} catch (Exception exception) {
createAndShowDialog(exception, "Error");
}
return null;
}
}.execute();
}
## How to: Work with untyped data
The untyped programming model gives you exact control over the JSON serialization, and there are some scenarios where you may wish to use it, for example, if your mobile service table contains a large number of columns and you only need to reference a few of them. Using the typed model requires you to define all of the mobile service table's columns in your data class. But with the untyped model you only define the columns you need to use.
Most of the API calls for accessing data are similar to the typed programming calls. The main difference is that in the untyped model you invoke methods on the **MobileServiceJsonTable** object, instead of the **MobileServiceTable** object.
### How to: Create an instance of an untyped table
Similar to the typed model, you start by getting a table reference, but in this case it's a [MobileServicesJsonTable](http://go.microsoft.com/fwlink/p/?LinkId=298733) object. You get the reference by calling the [getTable()](http://go.microsoft.com/fwlink/p/?LinkId=298734) method on an instance of the Mobile Services client.
First you define the variable:
/**
* Mobile Service Json Table used to access untyped data
*/
private MobileServiceJsonTable mJsonToDoTable;
Once you create an instance of the Mobile Services client in the **onCreate** method (here, the *mClient* variable), you next create an instance of a **MobileServiceJsonTable**, with the following code.
// Get the Mobile Service Json Table to use
mJsonToDoTable = mClient.getTable("ToDoItem");
Once you have created an instance of the **MobileServiceJsonTable**, you can call almost all of the methods on it that you can with the typed programming model. However in some cases the methods take an untyped parameter, as we see in the following examples.
### How to: Insert into an untyped table
The following code shows how to do an insert. The first step is to create a [**JsonObject**](http://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/JsonObject.html), which is part of the gson library.
JsonObject item = new JsonObject();
item.addProperty("text", "Wake up");
item.addProperty("complete", false);
The next step is to insert the object. The callback function passed to the [**insert**](http://go.microsoft.com/fwlink/p/?LinkId=298535) method is an instance of the [**TableJsonOperationCallback**](http://go.microsoft.com/fwlink/p/?LinkId=298532) class. Note how the parameter of the *insert* method is a JsonObject.
// Insert the new item
new AsyncTask() {
@Override
protected Void doInBackground(Void... params) {
try {
mJsonToDoTable.insert(item).get();
refreshItemsFromTable();
} catch (Exception exception) {
createAndShowDialog(exception, "Error");
}
return null;
}
}.execute();
If you need to get the ID of the inserted object, use this method call:
jsonObject.getAsJsonPrimitive("id").getAsInt());
### How to: Delete from an untyped table
The following code shows how to delete an instance, in this case, the same instance of a **JsonObject** that was created in the prior *insert* example. Note that the code is the same as with the typed case, but the method has a different signature since it references an **JsonObject**.
mToDoTable.delete(item);
You can also delete an instance directly by using its ID:
mToDoTable.delete(ID);
### How to: Return all rows from an untyped table
The following code shows how to retrieve an entire table. Since you are using a JSON Table, you can selectively retrieve only some of the table's columns.
public void showAllUntyped(View view) {
new AsyncTask() {
@Override
protected Void doInBackground(Void... params) {
try {
final JsonElement result = mJsonToDoTable.execute().get();
final JsonArray results = result.getAsJsonArray();
runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.clear();
for (JsonElement item : results) {
String ID = item.getAsJsonObject().getAsJsonPrimitive("id").getAsString();
String mText = item.getAsJsonObject().getAsJsonPrimitive("text").getAsString();
Boolean mComplete = item.getAsJsonObject().getAsJsonPrimitive("complete").getAsBoolean();
ToDoItem mToDoItem = new ToDoItem();
mToDoItem.setId(ID);
mToDoItem.setText(mText);
mToDoItem.setComplete(mComplete);
mAdapter.add(mToDoItem);
}
}
});
} catch (Exception exception) {
createAndShowDialog(exception, "Error");
}
return null;
}
}.execute();
}
You can do filtering, sorting and paging by concatenating methods that have the same names as those used in the typed programming model.
## How to: Bind data to the user interface
Data binding involves three components:
- the data source
- the screen layout
- and the adapter that ties the two together.
In our sample code, we return the data from the mobile service table *ToDoItem* into an array. This is one very common pattern for data applications: database queries typically return a collection of rows which the client gets in a list or array. In this sample the array is the data source.
The code specifies a screen layout that defines the view of the data that will appear on the device.
And the two are bound together with an adapter, which in this code is an extension of the *ArrayAdapter<ToDoItem>* class.
### How to: Define the Layout
The layout is defined by several snippets of XML code. Given an existing layout, let's assume the following code represents the **ListView** we want to populate with our server data.
In the above code the *listitem* attribute specifies the id of the layout for an individual row in the list. Here is that code, which specifies a check box and its associated text. This gets instantiated once for each item in the list. A more complex layout would specify additional fields in the display. This code is in the *row_list_to_do.xml* file.
### How to: Define the adapter
Since the data source of our view is an array of *ToDoItem*, we subclass our adapter from a *ArrayAdapter<ToDoItem>* class. This subclass will produce a View for every *ToDoItem* using the *row_list_to_do* layout.
In our code we define the following class which is an extension of the *ArrayAdapter<E>* class:
public class ToDoItemAdapter extends ArrayAdapter {
You must override the adapter's *getView* method. This sample code is one example of how to do this: details will vary with your application.
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
final ToDoItem currentItem = getItem(position);
if (row == null) {
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
row = inflater.inflate(R.layout.row_list_to_do, parent, false);
}
row.setTag(currentItem);
final CheckBox checkBox = (CheckBox) row.findViewById(R.id.checkToDoItem);
checkBox.setText(currentItem.getText());
checkBox.setChecked(false);
checkBox.setEnabled(true);
return row;
}
We create an instance of this class in our Activity as follows:
ToDoItemAdapter mAdapter;
mAdapter = new ToDoItemAdapter(this, R.layout.row_list_to_do);
Note that the second parameter to the ToDoItemAdapter constructor is a reference to the layout. The call to the constructor is followed by the following code which first gets a reference to the **ListView**, and next calls *setAdapter* to configure itself to use the adapter we just created:
ListView listViewToDo = (ListView) findViewById(R.id.listViewToDo);
listViewToDo.setAdapter(mAdapter);
### How to: Use the adapter
You are now ready to use data binding. The following code shows how to get the items in the mobile service table, clear the apapter, and then call the adapter's *add* method to fill it with the returned items.
public void showAll(View view) {
new AsyncTask() {
@Override
protected Void doInBackground(Void... params) {
try {
final MobileServiceList result = mToDoTable.execute().get();
runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.clear();
for (ToDoItem item : result) {
mAdapter.add(item);
}
}
});
} catch (Exception exception) {
createAndShowDialog(exception, "Error");
}
return null;
}
}.execute();
}
You must also call the adapter any time you modify the *ToDoItem* table if you want to display the results of doing that. Since modifications are done on a record by record basis, you will be dealing with a single row instead of a collection. When you insert an item you call the *add* method on the adapter, when deleting, you call the *remove* method.
## How to: Call a custom API
A custom API enables you to define custom endpoints that expose server functionality that does not map to an insert, update, delete, or read operation. By using a custom API, you can have more control over messaging, including reading and setting HTTP message headers and defining a message body format other than JSON. For an example of how to create a custom API in your mobile service, see [How to: define a custom API endpoint](mobile-services-dotnet-backend-define-custom-api.md).
### Update the app to call the custom API
1. We will add a button labelled "Complete All" next to the existing button, and move both buttons down a line. In Android Studio, open the *res\layout\activity_to_do.xml* file in your quickstart project, locate the **LinearLayout** element that contains the **Button** element named `buttonAddToDo`. Copy the **LinearLayout** and paste it immediately following the original one. Delete the **Button** element from the first **LinearLayout**.
2. In the second **LinearLayout**, delete the **EditText** element, and add the following code immediately following the existing **Button** element:
This adds a new button to the page, on a separate line, next to the existing button.
3. The second **LinearLayout** now looks like this:
4. Open the res\values\string.xml file and add the following line of code:
Complete All
5. In Project Explorer, right click the project name in the *src* folder (`com.example.{your projects name}`), choose **New** then **Class**. In the dialog, enter **MarkAllResult** in the class name field, choose OK, and replace the resulting class definition with the following code:
import com.google.gson.annotations.SerializedName;
public class MarkAllResult {
@SerializedName("count")
public int mCount;
public int getCount() {
return mCount;
}
public void setCount(int count) {
this.mCount = count;
}
}
This class is used to hold the row count value returned by the custom API.
6. Locate the **refreshItemsFromTable** method in the **ToDoActivity.java** file, and make sure that the first line of code in the `try` block looks like this:
final MobileServiceList result = mToDoTable.where().field("complete").eq(false).execute().get();
This filters the items so that completed items are not returned by the query.
7. Make sure that **ToDoActivity.java** contains the following imports at the beginning of the file:
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
8. In the **ToDoActivity.java** file, add the following method:
public void completeItem(View view) {
ListenableFuture result = mClient.invokeApi( "completeAll2", MarkAllResult.class );
Futures.addCallback(result, new FutureCallback() {
@Override
public void onFailure(Throwable exc) {
createAndShowDialog((Exception) exc, "Error");
}
@Override
public void onSuccess(MarkAllResult result) {
createAndShowDialog(result.getCount() + " item(s) marked as complete.", "Completed Items");
refreshItemsFromTable();
}
});
}
This method handles the **Click** event for the new button. The **invokeApi** method is called on the client, which sends a POST request to the new custom API. The result returned by the custom API is displayed in a message dialog, as are any errors.
### Test the app
1. From the **Run** menu, click **Run app** to start the project in the Android emulator, or in a connected Android device.
This executes your app, built with the Android SDK, that uses the client library to send a query that returns items from your mobile service.
2. In the app, type some text in **Insert a TodoItem**, then click **Add**.
3. Repeat the previous step until you have added several todo items to the list.
4. Click the **Complete All** button.

A message dialog is displayed that indicates the number of items marked complete and the filtered query is executed again, which clears all items from the list.
## How to: Authenticate users
Mobile Services supports authenticating and authorizing app users using a variety of external identity providers: Facebook, Google, Microsoft Account, Twitter, and Azure Active Directory. You can set permissions on tables to restrict access for specific operations to only authenticated users. You can also use the identity of authenticated users to implement authorization rules in your backend. For more information, see [Get started with authentication](http://go.microsoft.com/fwlink/p/?LinkId=296316).
Two authentication flows are supported: a *server* flow and a *client* flow. The server flow provides the simplest authentication experience, as it relies on the provider's web authentication interface. The client flow allows for deeper integration with device-specific capabilities such as single-sign-on as it relies on provider-specific device-specific SDKs.
Three steps are required to enable authentication in your app:
- Register your app for authentication with a provider, and configure Mobile Services
- Restrict table permissions to authenticated users only
- Add authentication code to your app
Mobile Services supports the following existing identity providers that you can use to authenticate users:
- Microsoft Account
- Facebook
- Twitter
- Google
- Azure Active Directory
You can set permissions on tables to restrict access for specific operations to only authenticated users. You can also use the ID of an authenticated user to modify requests.
These first two tasks are done using the [Azure classic portal](https://manage.windowsazure.com/). For more information, see [Get started with authentication](http://go.microsoft.com/fwlink/p/?LinkId=296316).
### How to: Add authentication code to your app
1. Add the following import statements to your app's activity file.
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import com.microsoft.windowsazure.mobileservices.authentication.MobileServiceAuthenticationProvider;
import com.microsoft.windowsazure.mobileservices.authentication.MobileServiceUser;
2. In the **onCreate** method of the activity class, add the following line of code after the code that creates the `MobileServiceClient` object: we assume that the reference to the `MobileServiceClient` object is *mClient*.
// Login using the Google provider.
ListenableFuture mLogin = mClient.login(MobileServiceAuthenticationProvider.Google);
Futures.addCallback(mLogin, new FutureCallback() {
@Override
public void onFailure(Throwable exc) {
createAndShowDialog((Exception) exc, "Error");
}
@Override
public void onSuccess(MobileServiceUser user) {
createAndShowDialog(String.format(
"You are now logged in - %1$2s",
user.getUserId()), "Success");
createTable();
}
});
This code authenticates the user using a Google login. A dialog is displayed which displays the ID of the authenticated user. You cannot proceed without a positive authentication.
> [AZURE.NOTE] If you are using an identity provider other than Google, change the value passed to the **login** method above to one of the following: _MicrosoftAccount_, _Facebook_, _Twitter_, or _WindowsAzureActiveDirectory_.
3. When you run the app, sign in with your chosen identity provider.
### How to: Cache authentication tokens
This section shows how to cache an authentication token. Do this to prevent users from having to authenticate again if app is "hibernated" while the token is still valid.
Caching authentication tokens requires you to store the User ID and authentication token locally on the device. The next time the app starts, you check the cache, and if these values are present, you can skip the log in procedure and re-hydrate the client with this data. However this data is sensitive, and it should be stored encrypted for safety in case the phone gets stolen.
The following code snippet demonstrates obtaining a token for a Microsoft Account log in. The token is cached and reloaded if the cache is found.
private void authenticate() {
if (LoadCache())
{
createTable();
}
else
{
// Login using the Google provider.
ListenableFuture mLogin = mClient.login(MobileServiceAuthenticationProvider.Google);
Futures.addCallback(mLogin, new FutureCallback() {
@Override
public void onFailure(Throwable exc) {
createAndShowDialog("You must log in. Login Required", "Error");
}
@Override
public void onSuccess(MobileServiceUser user) {
createAndShowDialog(String.format(
"You are now logged in - %1$2s",
user.getUserId()), "Success");
cacheUserToken(mClient.getCurrentUser());
createTable();
}
}); }
}
private boolean LoadCache()
{
SharedPreferences prefs = getSharedPreferences("temp", Context.MODE_PRIVATE);
String tmp1 = prefs.getString("tmp1", "undefined");
if (tmp1 == "undefined")
return false;
String tmp2 = prefs.getString("tmp2", "undefined");
if (tmp2 == "undefined")
return false;
MobileServiceUser user = new MobileServiceUser(tmp1);
user.setAuthenticationToken(tmp2);
mClient.setCurrentUser(user);
return true;
}
private void cacheUser(MobileServiceUser user)
{
SharedPreferences prefs = getSharedPreferences("temp", Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putString("tmp1", user.getUserId());
editor.putString("tmp2", user.getAuthenticationToken());
editor.commit();
}
So what happens if your token expires? In this case, when you try to use it to connect, you will get a *401 unauthorized* response. The user must then log in to obtain new tokens. You can avoid having to write code to handle this in every place in your app that calls your mobile service by using filters, which allow you to intercept calls to and responses from Mobile Services. The filter code will then test the response for a 401, trigger the sign-in process if needed, and then resume the request that generated the 401.
## How to: Customize the client
There are several ways for you to customize the default behavior of the Mobile Services client.
### How to: Customize request headers
You might want to attach a custom header to every outgoing request. You can accomplish that by configuring a **ServiceFilter** like this:
private class CustomHeaderFilter implements ServiceFilter {
@Override
public ListenableFuture handleRequest(
ServiceFilterRequest request,
NextServiceFilterCallback next) {
runOnUiThread(new Runnable() {
@Override
public void run() {
request.addHeader("My-Header", "Value"); }
});
SettableFuture result = SettableFuture.create();
try {
ServiceFilterResponse response = next.onNext(request).get();
result.set(response);
} catch (Exception exc) {
result.setException(exc);
}
}
### How to: Customize serialization
Mobile Services assumes by default that the table names, column names and data types on the server all match exactly what is on the client. But there can be any number of reasons why the server and client names might not match. One example might be if you have an existing client that you want to change so that it uses Mobile Services instead of a competitor's product.
You might want to do the following kinds of customizations:
- The column names used in the mobile- service table don't match the names you are using in the client
- Use a mobile service table that has a different name than the class it maps to in the client
- Turn on automatic property capitalization
- Add complex properties to an object
### How to: Map different client and server names
Suppose that your Java client code uses standard Java-style names for the *ToDoItem* object properties, such as the following.
- mId
- mText
- mComplete
- mDuration
You must serialize the client names into JSON names that match the column names of the *ToDoItem* table on the server. The following code, which makes use of the gson library does this.
@com.google.gson.annotations.SerializedName("text")
private String mText;
@com.google.gson.annotations.SerializedName("id")
private int mId;
@com.google.gson.annotations.SerializedName("complete")
private boolean mComplete;
@com.google.gson.annotations.SerializedName("duration")
private String mDuration;
### How to: Map different table names between client and mobile services
Mapping the client table name to a different mobile services table name is easy, we just use one of the overrides of the
getTable() function, as seen in the following code.
mToDoTable = mClient.getTable("ToDoItemBackup", ToDoItem.class);
### How to: Automate column name mappings
Mapping column names for a narrow table with only a few columns isn't a big deal, as we saw in the prior section. But suppose our table has a lot of columns, say 20 or 30. It turns out that we can call the gson API and specify a conversion strategy that will apply to every column, and avoid having to annotate every single column name.
To do this we use the gson library which the Android client library uses behind the scenes to serialize Java objects to JSON data, which is sent to Azure Mobile Services.
The following code uses the *setFieldNamingStrategy()* method, in which we define a *FieldNamingStrategy()* method. This method says to delete the initial character (an "m"), and then lower-case the next character, for every field name. This code also enables pretty-printing of the output JSON.
client.setGsonBuilder(
MobileServiceClient
.createMobileServiceGsonBuilder()
.setFieldNamingStrategy(new FieldNamingStrategy() {
public String translateName(Field field) {
String name = field.getName();
return Character.toLowerCase(name.charAt(1))
+ name.substring(2);
}
})
.setPrettyPrinting());
This code must be executed prior to any method calls on the Mobile Services client object.
### How to: Store an object or array property into a table
So far all of our serialization examples have involved primitive types such as integers and strings which easily serialize into JSON and into the mobile services table. Suppose we want to add a complex object to our client type, which doesn't automatically serialize to JSON and to the table. For example we might want to add an array of strings to the client object. It is now up to us to specify how to do the serialization, and how to store the array into the mobile services table.
To see an example of how to do this, check out the blog post Customizing serialization using the gson library in the Mobile Services Android client.
This general method can be used whenever we have a complex object that is not automatically serializable into JSON and the mobile services table.
[What is Mobile Services]: #what-is
[Concepts]: #concepts
[How to: Create the Mobile Services client]: #create-client
[How to: Create a table reference]: #instantiating
[The API structure]: #api
[How to: Query data from a mobile service]: #querying
[Return all Items]: #showAll
[Filter returned data]: #filtering
[Sort returned data]: #sorting
[Return data in pages]: #paging
[Select specific columns]: #selecting
[How to: Concatenate query methods]: #chaining
[How to: Bind data to the user interface]: #binding
[How to: Define the layout]: #layout
[How to: Define the adapter]: #adapter
[How to: Use the adapter]: #use-adapter
[How to: Insert data into a mobile service]: #inserting
[How to: update data in a mobile service]: #updating
[How to: Delete data in a mobile service]: #deleting
[How to: Look up a specific item]: #lookup
[How to: Work with untyped data]: #untyped
[How to: Authenticate users]: #authentication
[Cache authentication tokens]: #caching
[How to: Handle errors]: #errors
[How to: Design unit tests]: #tests
[How to: Customize the client]: #customizing
[Customize request headers]: #headers
[Customize serialization]: #serialization
[Next Steps]: #next-steps
[Setup and Prerequisites]: #setup
[Get started with Mobile Services]: mobile-services-android-get-started.md
[ASCII control codes C0 and C1]: http://en.wikipedia.org/wiki/Data_link_escape_character#C1_set
================================================
FILE: docs/mobile-services-android-upload-data-blob-storage.md
================================================
# Upload images to Azure Storage from an Android device
> [AZURE.SELECTOR-LIST (Platform | Backend)]
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-upload-data-blob-storage.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-upload-data-blob-storage.md)
- [(Android | Javascript)](mobile-services-android-upload-data-blob-storage.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This topic shows how to enable your Android Azure Mobile Services app to upload images to Azure Storage.
Mobile Services uses a SQL Database to store data. However, it's more efficient to store binary large object (BLOB) data in Azure Storage. In this tutorial you enable the Mobile Services quickstart app to take pictures with the Android camera, and upload the images to Azure Storage.
## What you need to get started
Before you start this tutorial, you must first complete the Mobile Services quickstart: [Get started with Mobile Services].
This tutorial also requires the following:
+ An [Azure Storage account](https://azure.microsoft.com/en-us/documentation/articles/storage-create-storage-account/)
+ An Android device with a camera
## How the app works
Uploading the photo image is a multistep process:
- First you take a photo, and insert a TodoItem row into the SQL database that contains new meta-data fields used by Azure Storage.
- A new mobile service SQL **insert** script asks Azure Storage for a Shared Access Signature (SAS).
- That script returns the SAS and a URI for the blob to the client.
- The client uploads the photo, using the SAS and blob URI.
So what is a SAS?
It's not safe to store the credentials needed to upload data to the Azure Storage service inside your client app. Instead, you store these credentials in your mobile service and use them to generate a Shared Access Signature (SAS) that grants permission to upload a new image. The SAS, a credential with a 5 minute expiration, is returned securely by Mobile Services to the client app. The app then uses this temporary credential to upload the image. For more information, see [Shared Access Signatures, Part 1: Understanding the SAS Model](https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-shared-access-signature-part-1/)
## Code Sample
[Here](https://github.com/Azure/mobile-services-samples/tree/master/UploadImages) is the completed client source code part of this app. To run it you must complete the Mobile Services backend parts of this tutorial.
## Update the registered insert script in the Azure classic portal
A new insert script is registered that generates an SAS when a new Todo item is inserted.
0. If you haven't yet created your storage account, see [How To Create a Storage Account](https://azure.microsoft.com/en-us/documentation/articles/storage-create-storage-account/).
1. In the [Azure classic portal](https://manage.windowsazure.com/), click **Storage**, click the storage account, then click **Manage Keys**.
2. Make a note of the **Storage Account Name** and **Access Key**.

3. In your mobile service, click the **Configure** tab, scroll down to **App settings** and enter a **Name** and **Value** pair for each of the following that you obtained from the storage account, then click **Save**.
+ `STORAGE_ACCOUNT_NAME`
+ `STORAGE_ACCOUNT_ACCESS_KEY`

The storage account access key is stored encrypted in app settings. You can access this key from any server script at runtime. For more information, see [App settings].
4. In the Configure tab, make sure that [Dynamic schema](http://msdn.microsoft.com/library/windowsazure/b6bb7d2d-35ae-47eb-a03f-6ee393e170f7) is enabled. You need dynamic schema enabled to be able to add new columns to the TodoItem table. Dynamic schema should not be enabled in any production service.
4. Click the **Data** tab and then click the **TodoItem** table.
5. In **todoitem**, click the **Script** tab and select **Insert**, replace the insert function with the following code, then click **Save**:
var azure = require('azure');
var qs = require('querystring');
var appSettings = require('mobileservice-config').appSettings;
function insert(item, user, request) {
// Get storage account settings from app settings.
var accountName = appSettings.STORAGE_ACCOUNT_NAME;
var accountKey = appSettings.STORAGE_ACCOUNT_ACCESS_KEY;
var host = accountName + '.blob.core.windows.net';
if ((typeof item.containerName !== "undefined") && (
item.containerName !== null)) {
// Set the BLOB store container name on the item, which must be lowercase.
item.containerName = item.containerName.toLowerCase();
// If it does not already exist, create the container
// with public read access for blobs.
var blobService = azure.createBlobService(accountName, accountKey, host);
blobService.createContainerIfNotExists(item.containerName, {
publicAccessLevel: 'blob'
}, function(error) {
if (!error) {
// Provide write access to the container for the next 5 mins.
var sharedAccessPolicy = {
AccessPolicy: {
Permissions: azure.Constants.BlobConstants.SharedAccessPermissions.WRITE,
Expiry: new Date(new Date().getTime() + 5 * 60 * 1000)
}
};
// Generate the upload URL with SAS for the new image.
var sasQueryUrl =
blobService.generateSharedAccessSignature(item.containerName,
item.resourceName, sharedAccessPolicy);
// Set the query string.
item.sasQueryString = qs.stringify(sasQueryUrl.queryString);
// Set the full path on the new new item,
// which is used for data binding on the client.
item.imageUri = sasQueryUrl.baseUrl + sasQueryUrl.path;
} else {
console.error(error);
}
request.execute();
});
} else {
request.execute();
}
}
This replaces the function that is invoked when an insert occurs in the TodoItem table with a new script. This new script generates a new SAS for the insert, which is valid for 5 minutes, and assigns the value of the generated SAS to the `sasQueryString` property of the returned item. The `imageUri` property is also set to the resource path of the new BLOB to enable image display during binding in the client UI.
>[AZURE.NOTE] This code creates an SAS for an individual BLOB. If you need to upload multiple blobs to a container using the same SAS, you can instead call the [generateSharedAccessSignature method](http://go.microsoft.com/fwlink/?LinkId=390455) with an empty blob resource name, like this:
>
> blobService.generateSharedAccessSignature(containerName, '', sharedAccessPolicy);
Next, you will update the quickstart app to add image upload functionality by using the SAS generated on insert.
[App settings]: http://msdn.microsoft.com/library/windowsazure/b6bb7d2d-35ae-47eb-a03f-6ee393e170f7
## Update the quickstart app to capture and upload images.
### Reference the Azure Storage Android client library
1. To add the reference to the library, in the **app** > **build.gradle** file, add this line to the `dependencies` section:
compile 'com.microsoft.azure.android:azure-storage-android:0.6.0@aar'
2. Change the `minSdkVersion` value to 15 (required by the camera API).
3. Press the **Sync Project with Gradle Files** icon.
### Update the manifest file for camera and storage
1. Specify your app requires having a camera available by adding this line to **AndroidManifest.xml**:
2. Specify your app needs permission to write to external storage by adding this line to **AndroidManifest.xml**:
Note that Android external storage is not necessarily an SD card: for more see [Saving Files](http://developer.android.com/training/basics/data-storage/files.html).
### Update resource files for the new user interface
1. Add titles for new buttons by adding the following to the **strings.xml** file in the *values* directory:
Take PhotoUpload
2. In the **activity_to_do.xml** file in the **res => layout** folder, add this code before the existing code for the **Add** button.
3. Replace the **Add** button element with the following code:
### Add code for photo capture
1. In **ToDoActivity.java** add this code to create a **File** object with a unique name.
// Create a File object for storing the photo
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
return image;
}
5. Add this code to start the Android camera app. You can then take pictures, and when one looks OK, press **Save**, which will store it in the file you just created.
// Run an Intent to start up the Android camera
static final int REQUEST_TAKE_PHOTO = 1;
public Uri mPhotoFileUri = null;
public File mPhotoFile = null;
public void takePicture(View view) {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
try {
mPhotoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
//
}
// Continue only if the File was successfully created
if (mPhotoFile != null) {
mPhotoFileUri = Uri.fromFile(mPhotoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mPhotoFileUri);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}
### Add code to upload photo file to blob storage
1. First we add some new meta-data fields to the `ToDoItem` object by adding this code to **ToDoItem.java**.
/**
* imageUri - points to location in storage where photo will go
*/
@com.google.gson.annotations.SerializedName("imageUri")
private String mImageUri;
/**
* Returns the item ImageUri
*/
public String getImageUri() {
return mImageUri;
}
/**
* Sets the item ImageUri
*
* @param ImageUri
* Uri to set
*/
public final void setImageUri(String ImageUri) {
mImageUri = ImageUri;
}
/**
* ContainerName - like a directory, holds blobs
*/
@com.google.gson.annotations.SerializedName("containerName")
private String mContainerName;
/**
* Returns the item ContainerName
*/
public String getContainerName() {
return mContainerName;
}
/**
* Sets the item ContainerName
*
* @param ContainerName
* Uri to set
*/
public final void setContainerName(String ContainerName) {
mContainerName = ContainerName;
}
/**
* ResourceName
*/
@com.google.gson.annotations.SerializedName("resourceName")
private String mResourceName;
/**
* Returns the item ResourceName
*/
public String getResourceName() {
return mResourceName;
}
/**
* Sets the item ResourceName
*
* @param ResourceName
* Uri to set
*/
public final void setResourceName(String ResourceName) {
mResourceName = ResourceName;
}
/**
* SasQueryString - permission to write to storage
*/
@com.google.gson.annotations.SerializedName("sasQueryString")
private String mSasQueryString;
/**
* Returns the item SasQueryString
*/
public String getSasQueryString() {
return mSasQueryString;
}
/**
* Sets the item SasQueryString
*
* @param SasQueryString
* Uri to set
*/
public final void setSasQueryString(String SasQueryString) {
mSasQueryString = SasQueryString;
}
2. Replace the 0-parameter constructor with this code:
/**
* ToDoItem constructor
*/
public ToDoItem() {
mContainerName = "";
mResourceName = "";
mImageUri = "";
mSasQueryString = "";
}
3. Replace the multi-parameter constructor with this code:
/**
* Initializes a new ToDoItem
*
* @param text
* The item text
* @param id
* The item id
*/
public ToDoItem(String text,
String id,
String containerName,
String resourceName,
String imageUri,
String sasQueryString) {
this.setText(text);
this.setId(id);
this.setContainerName(containerName);
this.setResourceName(resourceName);
this.setImageUri(imageUri);
this.setSasQueryString(sasQueryString);
}
4. In the **ToDoActivity.java** file, replace the **addItem** method in **ToDoActivity.java** with the following code that uploads the image.
/**
* Add a new item
*
* @param view
* The view that originated the call
*/
public void uploadPhoto(View view) {
if (mClient == null) {
return;
}
// Create a new item
final ToDoItem item = new ToDoItem();
item.setText(mTextNewToDo.getText().toString());
item.setComplete(false);
item.setContainerName("todoitemimages");
// Use a unigue GUID to avoid collisions.
UUID uuid = UUID.randomUUID();
String uuidInString = uuid.toString();
item.setResourceName(uuidInString);
// Send the item to be inserted. When blob properties are set this
// generates an SAS in the response.
AsyncTask task = new AsyncTask(){
@Override
protected Void doInBackground(Void... params) {
try {
final ToDoItem entity = addItemInTable(item);
// If we have a returned SAS, then upload the blob.
if (entity.getSasQueryString() != null) {
// Get the URI generated that contains the SAS
// and extract the storage credentials.
StorageCredentials cred =
new StorageCredentialsSharedAccessSignature(entity.getSasQueryString());
URI imageUri = new URI(entity.getImageUri());
// Upload the new image as a BLOB from a stream.
CloudBlockBlob blobFromSASCredential =
new CloudBlockBlob(imageUri, cred);
blobFromSASCredential.uploadFromFile(mPhotoFileUri.getPath());
}
runOnUiThread(new Runnable() {
@Override
public void run() {
if(!entity.isComplete()){
mAdapter.add(entity);
}
}
});
} catch (final Exception e) {
createAndShowDialogFromTask(e, "Error");
}
return null;
}
};
runAsyncTask(task);
mTextNewToDo.setText("");
}
This code sends a request to the mobile service to insert a new TodoItem. The response contains the SAS, which is then used to upload the image from local storage to a blob in Azure storage.
## Test uploading the images
1. In Android Studio press **Run**. In the dialogue, choose the device to use.
2. When the app UI appears, enter text in the textbox labeled **Add a ToDo item**.
3. Press **Take Photo**. When the camera app starts, take a photo. Press the check mark to accept the photo.
4. Press **Upload**. Note how the ToDoItem has been added to the list, as usual.
5. In the Azure classic portal, go to your storage account and press the **Containers** tab, and press the name of your container in the list.
6. A list of your uploaded blob files will appear. Select one and press **Download**.
7. The image that you uploaded now appears in a browser window.
## Next steps
Now that you have been able to securely upload images by integrating your mobile service with the Blob service, check out some of the other backend service and integration topics:
+ [Send email from Mobile Services with SendGrid]
Learn how to add email functionality to your Mobile Service using the SendGrid email service. This topic demonstrates how to add server side scripts to send email using SendGrid.
+ [Schedule backend jobs in Mobile Services]
Learn how to use the Mobile Services job scheduler functionality to define server script code that is executed on a schedule that you define.
+ [Mobile Services server script reference]
Reference topics for using server scripts to perform server-side tasks and integration with other Azure components and external resources.
+ [Mobile Services .NET How-to Conceptual Reference]
Learn more about how to use Mobile Services with .NET
[Install the Storage Client library]: #install-storage-client
[Update the client app to capture images]: #add-select-images
[Update the insert script to generate an SAS]: #update-scripts
[Upload images to test the app]: #test
[Next Steps]:#next-steps
[2]: ./media/mobile-services-windows-store-dotnet-upload-data-blob-storage/mobile-add-storage-nuget-package-dotnet.png
[Send email from Mobile Services with SendGrid]: store-sendgrid-mobile-services-send-email-scripts.md
[Schedule backend jobs in Mobile Services]: mobile-services-schedule-recurring-tasks.md
[Send push notifications to Windows Store apps using Service Bus from a .NET back-end]: http://go.microsoft.com/fwlink/?LinkId=277073&clcid=0x409
[Mobile Services server script reference]: mobile-services-how-to-use-server-scripts.md
[Get started with Mobile Services]: mobile-services-javascript-backend-windows-store-dotnet-get-started.md
[Azure classic portal]: https://manage.windowsazure.com/
[How To Create a Storage Account]: https://azure.microsoft.com/en-us/documentation/articles/storage-create-storage-account/
[Azure Storage Client library for Store apps]: http://go.microsoft.com/fwlink/p/?LinkId=276866
[Mobile Services .NET How-to Conceptual Reference]: mobile-services-windows-dotnet-how-to-use-client-library.md
[App settings]: http://msdn.microsoft.com/library/windowsazure/b6bb7d2d-35ae-47eb-a03f-6ee393e170f7
================================================
FILE: docs/mobile-services-concepts-links.md
================================================
# Mobile Services concepts
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
The topics linked below provide information about specific behaviors of Microsoft Azure Mobile Services. These same topics are available as help in the Azure classic portal.
## What is Mobile Services
Azure Mobile Services is a highly scalable mobile application development platform that lets you add enhanced functionality to your mobile device apps by using Azure.
With Mobile Services you can:
+ **Build native and cross platform apps** - Connect your iOS, Android, Windows, or cross-platform Xamarin or Cordova (Phonegap) apps to your backend mobile service using native SDKs.
+ **Send push notifications to your users** - Send push notifications to your users of your app.
+ **Authenticate your users** - Leverage popular identity providers like Facebook and Twitter to authenticate your app users.
+ **Store data in the cloud** - Store user data in a SQL Database (by default) or in Mongo DB, DocumentDB, Azure Tables, or Azure Blobs.
+ **Build offline-ready apps with sync** - Make your apps work offline and use Mobile Services to sync data in the background.
+ **Monitor and scale your apps** - Monitor app usage and scale your backend as demand grows.
## Mobile Services Concepts
The following are important features and concepts in the Mobile Services:
+ **Application key:** a unique value that is used to limit access to your mobile service from random clients; this "key" is not a security token and is not used to authenticate users of your app.
+ **Backend:** the mobile service instance that supports your app. A mobile service is implemented either as an ASP.NET Web API project (*.NET backend* ) or as a Node.js project (*JavaScript backend*).
+ **Identity provider:** an external service, trusted by Mobile Services, that authenticates your app's users. Supported providers include: Facebook, Twitter, Google, Microsoft Account, and Azure Active Directory.
+ **Push notification:** Service-initiated message that is sent to a registered device or user using Azure Notification Hubs.
+ **Scale:** The ability to add, for an additional cost, more processing power, performance, and storage as your app becomes more popular.
+ **Scheduled job:** Custom code that is run either on a pre-determined schedule or on-demand.
For more information, see [Mobile Services Concepts](./
mobile-services-concepts-links.md).
The [overview topic](https://msdn.microsoft.com/library/azure/jj193167.aspx) describes the benefits of using Mobile Services and what tasks can be performed in the Azure classic portal. For more general information about Mobile Services and examples of how to use Mobile Services in your apps, see [Mobile Services Tutorials and Resources](https://azure.microsoft.com/documentation/services/mobile-services/).
## Configuration
The following topics provide information about creating, deleting and configuring Mobile Services:
- [Create a mobile service](https://msdn.microsoft.com/library/azure/jj193169.aspx)
- [Delete a mobile service](https://msdn.microsoft.com/library/azure/jj193173.aspx)
- [Manage keys](https://msdn.microsoft.com/library/azure/jj193164.aspx)
- [Change the database](https://msdn.microsoft.com/library/azure/jj193170.aspx)
- [Scaling a mobile service](https://msdn.microsoft.com/library/azure/jj193178.aspx)
- [Configure identity](https://msdn.microsoft.com/library/azure/jj591527.aspx)
## Data access
The following topics provide information about accessing and changing app data stored in Mobile Services:
- [Work with data](https://msdn.microsoft.com/library/azure/jj631634.aspx)
- [Create a table](https://msdn.microsoft.com/library/azure/jj193162.aspx)
- [Permissions](https://msdn.microsoft.com/library/azure/jj193161.aspx)
- [Dynamic schema](https://msdn.microsoft.com/library/azure/jj193175.aspx)
- [Browse records](https://msdn.microsoft.com/library/azure/jj193171.aspx)
- [Delete data](https://msdn.microsoft.com/library/azure/jj908633.aspx)
- [Manage columns](https://msdn.microsoft.com/library/azure/jj193177.aspx)
- [System columns](https://msdn.microsoft.com/library/azure/dn518225.aspx)
## Push notifications
The following topics provide information about configuring push notifications in Mobile Services:
- [Configure push notifications](https://msdn.microsoft.com/library/azure/jj591526.aspx)
- [Register endpoint](https://msdn.microsoft.com/library/azure/dn771685.aspx)
- [Send push notifications](https://msdn.microsoft.com/library/azure/jj631630.aspx)
## Scheduled jobs
The following topics provide information about working with scheduled jobs:
- [Schedule jobs](https://msdn.microsoft.com/library/azure/jj860528.aspx)
- [Configure jobs](https://msdn.microsoft.com/library/azure/jj899833.aspx)
- [Register job scripts](https://msdn.microsoft.com/library/azure/jj899832.aspx)
## Custom APIs
The following topics provide information about defining custom HTTP endpoints in Mobile Services:
- [Custom API](https://msdn.microsoft.com/library/azure/dn280974.aspx)
- [Content types and headers](https://msdn.microsoft.com/library/azure/dn303369.aspx)
## JavaScript backend server scripts
The following topics provide examples of how to perform tasks using server scripts in a JavaScript backend mobile services:
- [Using scripts](https://msdn.microsoft.com/library/azure/jj193174.aspx)
- [Script debugging](https://msdn.microsoft.com/library/azure/jj631636.aspx)
- [Read and write data](https://msdn.microsoft.com/library/azure/jj631640.aspx)
- [Modify the request](https://msdn.microsoft.com/library/azure/jj631635.aspx)
- [Modify the response](https://msdn.microsoft.com/library/azure/jj631631.aspx)
- [Validate data](https://msdn.microsoft.com/library/azure/jj631638.aspx)
- [Send push notification](https://msdn.microsoft.com/library/azure/jj631630.aspx)
- [Send HTTP request](https://msdn.microsoft.com/library/azure/jj631641.aspx)
- [Authorize user](https://msdn.microsoft.com/library/azure/jj631637.aspx)
- [Restrict access to admins](https://msdn.microsoft.com/library/azure/jj712649.aspx)
- [Error handling](https://msdn.microsoft.com/library/azure/jj631632.aspx)
- [Shortcut keys](https://msdn.microsoft.com/library/azure/jj552469.aspx)
================================================
FILE: docs/mobile-services-disaster-recovery.md
================================================
# Recover your mobile service in the event of a disaster
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
When you use Azure Mobile Services to deploy an app, you can use its built-in features to ensure business continuity in the event of availability problems, such as server failures, network disruptions, data loss, and widespread facilities loss. By deploying your app using Azure Mobile Services you are taking advantage of many fault tolerance and infrastructure capabilities that you would have to design, implement, and manage if you were to deploy a traditional on-premise solution. Azure mitigates a large fraction of potential failures at a fraction of the cost.
## Prepare for possible disasters
To make recovery easier in case of an availability problem, you can prepare for it in advance:
+ **Back up your data in the Azure mobile service SQL Database**
Your mobile service application data is stored in an Azure SQL Database. We recommend that you back it up as prescribed in the [SQL Database business continuity guidance].
+ **Back up your mobile service scripts**
We recommend that you store your mobile service scripts in a source-control system such as [Team Foundation Service] or [GitHub] and not rely only on the copies in the mobile service itself. You can download the scripts via the Azure classic portal, using the Mobile Services [source control feature], or [using the Azure CLI]. Pay close attention to features labeled as "preview" in the Azure classic portal, as recovery for those scripts is not guaranteed and you might need to recover them from your own source control original.
+ **Reserve a secondary mobile service**
In the event of an availability problem with your mobile service, you may have to redeploy it to an alternate Azure region. To ensure capacity is available (for example under rare circumstances such as the loss of an entire region), we recommend that you create a secondary mobile service in your alternate region and set its mode the same as or higher than the mode of your primary service. (If your primary service is in Basic mode, you can make the secondary service either Basic or Standard. But if the primary is Standard, then the secondary must also be Standard.)
## Watch for signs of a problem
These circumstances indicate a problem that might require a recovery operation:
+ Apps that are connected to your mobile service can't communicate with it for an extended period of time.
+ Mobile service status is displayed as **Unhealthy** in the [Azure classic portal].
+ An **Unhealthy** banner appears at the top of every tab for your mobile service in the Azure classic portal, and management operations produce error messages.
+ The [Azure Service Dashboard] indicates an availability problem.
## Recover from a disaster
When a problem occurs, use the Service Dashboard to get guidance and updates.
If you're prompted by the Service Dashboard, execute the following steps to restore your mobile service to a running state in an alternate Azure region. If you created a secondary service in advance, its capacity will be used to restore the primary service. Because the URL and application key of the primary service is unchanged after recovery, you don't have to update any apps that refer to it.
To recover your mobile service after an outage:
1. In the Azure classic portal, ensure that the status of your service is reported as **Unhealthy**.
2. If you already reserved a secondary mobile service, you can skip this step.
If you haven't already reserved a secondary mobile service, create one now in another Azure region. Set its scale mode the same as the mode of your primary service.
3. Configure the Azure Command-Line Interface (Azure CLI) to work with your subscription, as described in [Automate mobile services with the Azure CLI].
4. Now you can use your secondary service to recover your primary one.
> [AZURE.IMPORTANT] In addition to migrating your files, the migrate command also updates the host name of your primary service to point to your secondary service so that client applications do not need to be updated. However, it will take up to 30 minutes for the host name to resolve to the new service. For this reason, it is recommended that the migrate command only be used in disaster recovery scenarios.
> [AZURE.IMPORTANT] When you execute the command in this step, the secondary service is deleted so that its capacity can be used to recover the primary service. We recommend that you back up your scripts and settings before you run the command, if you would like to keep them.
When you're ready, execute this command:
azure mobile migrate PrimaryService SecondaryService
info: Executing command mobile migrate
Warning: this action will use the capacity from the mobile service 'SecondaryService' and delete it and the host name for 'PrimaryService' may not resolve for up to 30 minutes. Do you want to migrate the mobile service 'PrimaryService'? [y/n]: y
+ Performing migration
+ Migration with id '0123456789abcdef0123456789abcdef' started. The migration may take several minutes to complete.
+ Cleaning up
info: Migration complete. It may take 30 minutes for DNS to resolve to the migrated site.
info: mobile migrate command OK
> [AZURE.NOTE] It may take a few minutes after the command completes until you can see the changes in the Azure classic portal.
5. Verify that all scripts have been recovered correctly by comparing them to your originals in source control. In most cases, scripts are automatically recovered without data loss, but if you find a discrepancy, you can recover that script manually.
6. Make sure that your recovered service is communicating with your Azure SQL Database. The recover command recovers the mobile service, but retains the connection to the original database. If the problem in the primary Azure region also affects the database, the recovered service may still not be running correctly. You can use the Azure Service Dashboard to examine the database status for a given region. If the original database is not working, you can recover it:
+ Recover your Azure SQL Database to the Azure region where you just recovered your mobile service, as described in [SQL Database business continuity guidance].
+ In the Azure classic portal, on the **"Configure"** tab of your mobile service, choose "Change database" and then select the newly recovered database.
7. Your mobile service is now hosted in a different physical location. You'll need to update your publishing and/or git credentials to allow for updating your running site.
+ If you are using a **.NET backend**, set up your publishing profile again, as described in [Publish your mobile service](mobile-services-dotnet-backend-windows-store-dotnet-get-started.md#publish-your-mobile-service). This will update your publishing details to point to the new service location.
+ If you are using a **Javascript backend** and managing your service with the Portal, you don't need to take any extra action.
+ If you are using a **Javascript backend** and managing your service with node, update your git remote to point to the new repository. To do this, you remove the .git file path from your git remote:
1. Find your current origin remote:
git remote -v
origin https://myservice.scm.azure-mobile.net/myservice.git (fetch)
origin https://myservice.scm.azure-mobile.net/myservice.git (push)
3. Update the remote using the same url, but without the final .git file path:
git remote set-url origin https://myservice.scm.azure-mobile.net
4. Pull from origin to verify that it is working correctly.
Now you should be in a state where your mobile service has been recovered to a new Azure region and is now accepting traffic from your store apps using its original URL.
[SQL Database business continuity guidance]: http://msdn.microsoft.com/library/windowsazure/hh852669.aspx
[Team Foundation Service]: http://tfs.visualstudio.com/
[Github]: https://github.com/
[source control feature]: http://www.windowsazure.comhttps://azure.microsoft.com/develop/mobile/tutorials/store-scripts-in-source-control/
[using the Azure CLI]: http://www.windowsazure.comhttps://azure.microsoft.com/develop/mobile/tutorials/command-line-administration/
[Azure classic portal]: http://manage.windowsazure.com/
[Azure Service Dashboard]: http://www.windowsazure.com/support/service-dashboard/
[Automate mobile services with the Azure CLI]: http://www.windowsazure.comhttps://azure.microsoft.com/develop/mobile/tutorials/command-line-administration/
================================================
FILE: docs/mobile-services-dotnet-backend-android-get-started-push.md
================================================
# Add push notifications to your Mobile Services app
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-push.md)
- [(iOS | JavaScript)](mobile-services-javascript-backend-ios-get-started-push.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-push.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-get-started-push.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-javascript-backend-windows-phone-get-started-push.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started-push.md)
- [(Android | Javascript)](mobile-services-javascript-backend-android-get-started-push.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-push.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-push.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-push.md)
- [(Xamarin.Forms | JavaScript)](partner-xamarin-mobile-services-xamarin-forms-get-started-push.md)
This topic shows how to use Azure Mobile Services to send push notifications to your Android app. In this tutorial you add push notifications using Google Cloud Messaging (GCM) to the quickstart project. When complete, your mobile service will send a push notification each time a record is inserted.
This tutorial is based on the Mobile Services quickstart. Before you start this tutorial, you must first complete [Get started with Mobile Services] to connect your project to the mobile service. As such, this tutorial also requires Visual Studio 2013.
## Sample code
To see the completed source code go [here](https://github.com/RickSaling/mobile-services-samples/tree/push/GettingStartedWithPush).
## Enable Google Cloud Messaging
1. Navigate to the [Google Cloud Console](https://console.developers.google.com/project), sign in with your Google account credentials.
2. Click **Create Project**, type a project name, then click **Create**. If requested, carry out the SMS Verification, and click **Create** again.

Type in your new **Project name** and click **Create project**.
3. Click the **Utilities and More** button and then click **Project Information**. Make a note of the **Project Number**. You will need to set this value as the `SenderId` variable in the client app.

4. In the project dashboard, under **Mobile APIs**, click **Google Cloud Messaging**, then on the next page click **Enable API** and accept the terms of service.


5. In the project dashboard, Click **Credentials** > **Create Credential** > **API Key**.

6. In **Create a new key**, click **Server key**, type a name for your key, then click **Create**.
7. Make a note of the **API KEY** value.
You will use this API key value to enable Azure to authenticate with GCM and send push notifications on behalf of your app.
## Configure your mobile service to send push requests
1. Log on to the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services**, and then click your app.
2. Click the **Push** tab, enter the **API Key** value obtained from GCM in the previous procedure, then click **Save**.

>[AZURE.NOTE]When you set your GCM credentials for enhanced push notifications in the Push tab in the portal, they are shared with Notification Hubs to configure the notification hub with your app.
Both your mobile service and your app are now configured to work with GCM and Notification Hubs.
## Update the mobile service to send push notifications
1. In Visual Studio Solution Explorer, expand the **Controllers** folder in the mobile service project. Open TodoItemController.cs. At the top of the file, add the following `using` statements:
using System;
using System.Collections.Generic;
2. Update the `PostTodoItem` method definition with the following code:
public async Task PostTodoItem(TodoItem item)
{
TodoItem current = await InsertAsync(item);
Dictionary data = new Dictionary()
{
{ "message", item.Text}
};
GooglePushMessage message = new GooglePushMessage(data, TimeSpan.FromHours(1));
try
{
var result = await Services.Push.SendAsync(message);
Services.Log.Info(result.State.ToString());
}
catch (System.Exception ex)
{
Services.Log.Error(ex.Message, null, "Push.SendAsync Error");
}
return CreatedAtRoute("Tables", new { id = current.Id }, current);
}
This code will send a push notification (with the text of the inserted item) after inserting a todo item. In the event of an error, the code will add an error log entry which is viewable on the **Logs** tab of the mobile service in the [Azure classic portal](https://manage.windowsazure.com/).
3. Republish your mobile service project to Azure.
## Add push notifications to your app
### Verify Android SDK Version
Because of ongoing development, the Android SDK version installed in Android Studio might not match the version in the code. The Android SDK referenced in this tutorial is version 21, the latest at the time of writing. The version number may increase as new releases of the SDK appear, and we recomend using the latest version available.
Two symptoms of version mismatch are:
1. When you Build or Rebuild the project, you may get Gradle error messages like "**failed to find target Google Inc.:Google APIs:n**".
2. Standard Android objects in code that should resolve based on `import` statements may be generating error messages.
If either of these appear, the version of the Android SDK installed in Android Studio might not match the SDK target of the downloaded project. To verify the version, make the following changes:
1. In Android Studio, click **Tools** => **Android** => **SDK Manager**. If you have not installed the latest version of the SDK Platform, then click to install it. Make a note of the version number.
2. In the Project Explorer tab, under **Gradle Scripts**, open the file **build.gradle (modeule: app)**. Ensure that the **compileSdkVersion** and **buildToolsVersion** are set to the latest SDK version installed. The tags might look like this:
compileSdkVersion 'Google Inc.:Google APIs:21'
buildToolsVersion "21.1.2"
3. In the Android Studio Project Explorer right-click the project node, choose **Properties**, and in the left column choose **Android**. Ensure that the **Project Build Target** is set to the same SDK version as the **targetSdkVersion**.
4. In Android Studio, the manifest file is no longer used to specify the target SDK and minimum SDK version, unlike the case with Eclipse.
Your next step is to install Google Play services. Google Cloud Messaging has some minimum API level requirements for development and testing, which the **minSdkVersion** property in the Manifest must conform to.
If you will be testing with an older device, then consult [Set Up Google Play Services SDK] to determine how low you can set this value, and set it appropriately.
### Add Google Play Services to the project
1. Open the Android SDK Manager by clicking the icon on the toolbar of Android Studio or by clicking **Tools** -> **Android** -> **SDK Manager** on the menu. Locate the target version of the Android SDK that is used in your project , open it, and choose **Google APIs**, if it is not already installed.
2. Scroll down to **Extras**, expand it, and choose **Google Play Services**, as shown below. Click **Install Packages**. Note the SDK path, for use in the following step.

3. Open the **build.gradle** file in the app directory.

4. Add this line under *dependencies*:
compile 'com.google.android.gms:play-services-gcm:8.4.0'
5. Under *defaultConfig*, change *minSdkVersion* to 9.
6. Click the **Sync Project with Gradle Files** icon in the tool bar.
7. Open **AndroidManifest.xml** and add this tag to the *application* tag.
### Add code
1. In your **app** project, open the file `AndroidManifest.xml`. In the code in the next two steps, replace _`**my_app_package**`_ with the name of the app package for your project, which is the value of the `package` attribute of the `manifest` tag.
2. Add the following new permissions after the existing `uses-permission` element:
3. Add the following code after the `application` opening tag:
4. Add this line under *dependencies* in the **build.gradle** file in the app directory and re-sync gradle with the project:
compile(group: 'com.microsoft.azure', name: 'azure-notifications-handler', version: '1.0.1', ext: 'jar')
5. Open the file *ToDoItemActivity.java*, and add the following import statement:
import com.microsoft.windowsazure.notifications.NotificationsManager;
6. Add the following private variable to the class: replace _``_ with the Project Number assigned by Google to your app in the preceding procedure:
public static final String SENDER_ID = "";
7. Change the definition of the *MobileServiceClient* from **private** to **public static**, so it now looks like this:
public static MobileServiceClient mClient;
8. Next we need to add a new class to handle notifications. In the Project Explorer, open the **src** => **main** => **java** nodes, and right-click the package name node: click **New**, then click **Java Class**.
9. In **Name** type `MyHandler`, then click **OK**.

10. In the MyHandler file, replace the class declaration with
public class MyHandler extends NotificationsHandler {
11. Add the following import statements for the `MyHandler` class:
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
12. Next add the following members for the `MyHandler` class:
public static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
Context ctx;
13. In the `MyHandler` class, add the following code to override the **onRegistered** method, which registers your device with the mobile service Notification Hub.
@Override
public void onRegistered(Context context, final String gcmRegistrationId) {
super.onRegistered(context, gcmRegistrationId);
new AsyncTask() {
protected Void doInBackground(Void... params) {
try {
ToDoActivity.mClient.getPush().register(gcmRegistrationId, null);
return null;
}
catch(Exception e) {
// handle error
}
return null;
}
}.execute();
}
14. In the `MyHandler` class, add the following code to override the **onReceive** method, which causes the notification to display when it is received.
@Override
public void onReceive(Context context, Bundle bundle) {
ctx = context;
String nhMessage = bundle.getString("message");
sendNotification(nhMessage);
}
private void sendNotification(String msg) {
mNotificationManager = (NotificationManager)
ctx.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(ctx, 0,
new Intent(ctx, ToDoActivity.class), 0);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(ctx)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Notification Hub Demo")
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(msg))
.setContentText(msg);
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
15. Back in the TodoActivity.java file, update the **onCreate** method of the *ToDoActivity* class to register the notification handler class. Make sure to add this code after the *MobileServiceClient* is instantiated.
NotificationsManager.handleNotifications(this, SENDER_ID, MyHandler.class);
Your app is now updated to support push notifications.
[Mobile Services Android SDK]: http://aka.ms/Iajk6q
## Test the app against the published mobile service
You can test the app by directly attaching an Android phone with a USB cable, or by using a virtual device in the emulator.
### Enable push notifications for local testing
You can optionally test push notifications with your mobile service running on the local computer or VM before you publish to Azure. To do this, you must set information about the notification hub used by your app in the web.config file. This information is only used when running locally to connect to the notification hub; it is ignored when published to Azure.
1. Back in the **Push** tab of your mobile service, click the **Notification Hub** link.

This navigates to the notification hub used by your mobile service.
2. In the notification hub page, make a note of the name of your notification hub, then click **View Connection String**.

3. In the **Access connection information**, copy the **DefaultFullSharedAccessSignature** connection string.

4. In your mobile service project in Visual Studio, open the Web.config file for the service and in **connectionStrings**, replace the connection string for **MS_NotificationHubConnectionString** with the connection string from the previous step.
5. In **appSettings**, replace the value of the **MS_NotificationHubName** app setting with the name of the notification hub.
Now, the mobile service project is configured to connect to the notification hub in Azure when running locally. Note that it is important to use the same notification hub name and connection string as the portal because these Web.config project settings are overridden by the portal settings when running in Azure.
4. Create a new class in the project called `ToDoBroadcastReceiver`.
5. Add the following using statements to **ToDoBroadcastReceiver** class:
using Gcm.Client;
using Microsoft.WindowsAzure.MobileServices;
6. Add the following permission requests between the **using** statements and the **namespace** declaration:
[assembly: Permission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "com.google.android.c2dm.permission.RECEIVE")]
//GET_ACCOUNTS is only needed for android versions 4.0.3 and below
[assembly: UsesPermission(Name = "android.permission.GET_ACCOUNTS")]
[assembly: UsesPermission(Name = "android.permission.INTERNET")]
[assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
7. Replace the existing **ToDoBroadcastReceiver** class definition with the following:
[BroadcastReceiver(Permission = Gcm.Client.Constants.PERMISSION_GCM_INTENTS)]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_MESSAGE },
Categories = new string[] { "@PACKAGE_NAME@" })]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_REGISTRATION_CALLBACK },
Categories = new string[] { "@PACKAGE_NAME@" })]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_LIBRARY_RETRY },
Categories = new string[] { "@PACKAGE_NAME@" })]
public class ToDoBroadcastReceiver : GcmBroadcastReceiverBase
{
// Set the Google app ID.
public static string[] senderIDs = new string[] { "" };
}
In the above code, you must replace _``_ with the project number assigned by Google when you provisioned your app in the Google developer portal.
8. In the ToDoBroadcastReceiver.cs project file, add the following code that defines the **PushHandlerService** class:
// The ServiceAttribute must be applied to the class.
[Service]
public class PushHandlerService : GcmServiceBase
{
public static string RegistrationID { get; private set; }
### Setting up the Android emulator for testing
When you run this app in the emulator, make sure that you use an Android Virtual Device (AVD) that supports Google APIs.
> [AZURE.IMPORTANT] In order to receive push notifications, you must set up a Google account on your Android Virtual Device (in the emulator, navigate to **Settings** and click **Add Account**). Also, make sure that the emulator is connected to the Internet.
1. From **Tools**, click **Open Android Emulator Manager**, select your device, and then click **Edit**.

2. Select **Google APIs** in **Target**, then click **OK**.

3. On the top toolbar, click **Run**, and then select your app. This starts the emulator and runs the app.
The app retrieves the *registrationId* from GCM and registers with the Notification Hub.
### Inserting a new item generates a notification.
1. In the app, type meaningful text, such as _A new Mobile Services task_ and then click the **Add** button.
2. Swipe down from the top of the screen to open the device's Notification Center to see the notification.

You have successfully completed this tutorial.
## Next steps
This tutorial demonstrated the basics of enabling an Android app to use Mobile Services and Notification Hubs to send push notifications. Next, consider completing the next tutorial, [Send push notifications to authenticated users], which shows how to use tags to send push notifications from your mobile service to only an authenticated user.
+ [Send broadcast notifications to subscribers]
Learn how users can register and receive push notifications for categories they're interested in.
+ [Send template-based notifications to subscribers]
Learn how to use templates to send push notifications from a Mobile Service, without having to craft platform-specific payloads in your back-end.
Learn more about Mobile Services and Notification Hubs in the following topics:
* [What are Notification Hubs?]
Learn more about how Notification Hubs works to deliver notifications to your apps across all major client platforms.
* [Debug Notification Hubs applications](http://go.microsoft.com/fwlink/p/?linkid=386630)
Get guidance troubleshooting and debugging Notification Hubs solutions.
* [How to use the Android client library for Mobile Services]
Learn more about how to use Mobile Services with Android.
[Create a new mobile service]: #create-service
[Download the service locally]: #download-the-service-locally
[Test the mobile service]: #test-the-service
[Download the GetStartedWithData project]: #download-app
[Update the app to use the mobile service for data access]: #update-app
[Test the Android App against the service hosted locally]: #test-locally-hosted
[Publish the mobile service to Azure]: #publish-mobile-service
[Test the Android App against the service hosted in Azure]: #test-azure-hosted
[Test the app against the published mobile service]: #test-app
[Next Steps]:#next-steps
[Get started with push notifications (Eclipse)]: mobile-services-dotnet-backend-android-get-started-push-ec.md
[Get started with Mobile Services]: mobile-services-dotnet-backend-android-get-started.md
[Mobile Services SDK]: http://go.microsoft.com/fwlink/p/?LinkId=257545
[How to use the Android client library for Mobile Services]: mobile-services-android-how-to-use-client-library.md
[What are Notification Hubs?]: https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-push-notification-overview/
[Send broadcast notifications to subscribers]: https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-aspnet-backend-android-xplat-segmented-gcm-push-notification/
[Send template-based notifications to subscribers]: https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-aspnet-backend-android-xplat-segmented-gcm-push-notification/
================================================
FILE: docs/mobile-services-dotnet-backend-android-get-started-users.md
================================================
# Add authentication to your Mobile Services Android app
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-users.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started-users.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-users.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-get-started-users.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-windows-phone-get-started-users.md)
- [(Android | Javascript)](mobile-services-android-get-started-users.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started-users.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-users.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-users.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-users.md)
- [(HTML | Javascript)](mobile-services-html-get-started-users.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
## Summary
This topic shows you how to authenticate users in Azure Mobile Services from your app. In this tutorial, you add authentication to the quickstart project using an identity provider that is supported by Mobile Services. After being successfully authenticated and authorized by Mobile Services, the user ID value is displayed.
This tutorial walks you through the basic steps to enable authentication in your app.
## Prerequisites
This tutorial is based on the code you download in the Mobile Services quickstart. Before you start this tutorial, you must first complete either [Get started with Mobile Services] or [Add Mobile Services to an existing app].
> [AZURE.IMPORTANT] If you completed the quickstart tutorial prior to the release of Azure Mobile Services Android SDK 2.0, you must re-do it, because the SDK is not backwards compatible. To verify the version, check the **dependencies** section of your project's **build.gradle** file.
## Register your app for authentication and configure Mobile Services
1. In the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Dashboard**, and make a note of the **Mobile Service URL** value.
2. Register your app with one or more of the following authentication providers:
* [Google](./
mobile-services-how-to-register-google-authentication.md)
* [Facebook](./
mobile-services-how-to-register-facebook-authentication.md)
* [Twitter](./
mobile-services-how-to-register-twitter-authentication.md)
* [Microsoft](./
mobile-services-how-to-register-microsoft-authentication.md)
* [Azure Active Directory](./
mobile-services-how-to-register-active-directory-authentication.md).
Make a note of the client identity and client secret values generated by the provider. Do not distribute or share the client secret.
3. Back in the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Identity** > your identity provider settings, then enter the client ID and secret value from your provider.
You've now configured both your app and your mobile service to work with your auth provider. You may optionally repeat all these steps for each additional identity provider you'd like to support.
> [AZURE.IMPORTANT] Verify that you've set the correct redirect URI on your identity provider's developer site. As described in the linked instructions for each provider above, the redirect URI may be different for a .NET backend service vs. for a JavaScript backend service. An incorrectly configured redirect URI may result in the login screen not being displayed properly and the app malfunctioning in unexpected ways.
### (Optional) Configure your .NET Mobile Service for Azure Active Directory
>[AZURE.NOTE] These steps are optional because they only apply to the Azure Active Directory login provider.
1. Install the [WindowsAzure.MobileServices.Backend.Security NuGet package](https://www.nuget.org/packages/WindowsAzure.MobileServices.Backend.Security).
2. In Visual Studio expand App_Start and open WebApiConfig.cs. Add the following `using` statement at the top:
using Microsoft.WindowsAzure.Mobile.Service.Security.Providers;
3. Also in WebApiConfig.cs, add the following code to the `Register` method, immediately after `options` is instantiated:
options.LoginProviders.Remove(typeof(AzureActiveDirectoryLoginProvider));
options.LoginProviders.Add(typeof(AzureActiveDirectoryExtendedLoginProvider));
## Restrict permissions to authenticated users
By default, all requests to mobile service resources are restricted to clients that present the application key, which does not strictly secure access to resources. To secure your resources, you must restrict access to only authenticated clients.
1. In Visual Studio, open your mobile service project, expand the Controllers folder, and open **TodoItemController.cs**. The **TodoItemController** class implements data access for the TodoItem table. Add the following `using` statement:
using Microsoft.WindowsAzure.Mobile.Service.Security;
2. Apply the following _AuthorizeLevel_ attribute to the **TodoItemController** class.
[AuthorizeLevel(AuthorizationLevel.User)]
This makes sure that all operations against the _TodoItem_ table require an authenticated user. You can also apply the *AuthorizeLevel* attribute at the method level.
3. (Optional) If you wish to debug authentication locally, expand the `App_Start` folder, open **WebApiConfig.cs**, and add the following code to the **Register** method.
config.SetIsHosted(true);
This tells the local mobile service project to run as if it is being hosted in Azure, including honoring the *AuthorizeLevel* settings. Without this setting, all HTTP requests to localhost are permitted without authentication despite the *AuthorizeLevel* setting. When you enable self-hosted mode, you also need to set a value for the local application key.
4. (Optional) In the web.config project file, set a string value for the `MS_ApplicationKey` app setting.
This is the password that you use (with no username) to test the API help pages when you run the service locally. This string value is not used by the live site in Azure, and you do not need to use the actual application key; any valid string value will work.
4. Republish your project.
3. Open the project that you created when you completed the tutorial [Get started with Mobile Services].
4. From the **Run** menu, then click **Run app** to start the app; verify that an unhandled exception with a status code of 401 (Unauthorized) is raised after the app starts.
This happens because the app attempts to access Mobile Services as an unauthenticated user, but the _TodoItem_ table now requires authentication.
Next, you will update the app to authenticate users before requesting resources from the mobile service.
## Add authentication to the app
1. In **Project Explorer** in Android Studio, open the ToDoActivity.java file and add the following import statements.
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import com.microsoft.windowsazure.mobileservices.authentication.MobileServiceAuthenticationProvider;
import com.microsoft.windowsazure.mobileservices.authentication.MobileServiceUser;
2. Add the following method to the **ToDoActivity** class:
private void authenticate() {
// Login using the Google provider.
ListenableFuture mLogin = mClient.login(MobileServiceAuthenticationProvider.Google);
Futures.addCallback(mLogin, new FutureCallback() {
@Override
public void onFailure(Throwable exc) {
createAndShowDialog((Exception) exc, "Error");
}
@Override
public void onSuccess(MobileServiceUser user) {
createAndShowDialog(String.format(
"You are now logged in - %1$2s",
user.getUserId()), "Success");
createTable();
}
});
}
This creates a new method to handle the authentication process. The user is authenticated by using a Google login. A dialog is displayed which displays the ID of the authenticated user. You cannot proceed without a positive authentication.
> [AZURE.NOTE] If you are using an identity provider other than Google, change the value passed to the **login** method above to one of the following: _MicrosoftAccount_, _Facebook_, _Twitter_, or _windowsazureactivedirectory_.
3. In the **onCreate** method, add the following line of code after the code that instantiates the `MobileServiceClient` object.
authenticate();
This call starts the authentication process.
4. Move the remaining code after `authenticate();` in the **onCreate** method to a new **createTable** method, which looks like this:
private void createTable() {
// Get the table instance to use.
mToDoTable = mClient.getTable(ToDoItem.class);
mTextNewToDo = (EditText) findViewById(R.id.textNewToDo);
// Create an adapter to bind the items with the view.
mAdapter = new ToDoItemAdapter(this, R.layout.row_list_to_do);
ListView listViewToDo = (ListView) findViewById(R.id.listViewToDo);
listViewToDo.setAdapter(mAdapter);
// Load the items from Azure.
refreshItemsFromTable();
}
9. From the **Run** menu, then click **Run app** to start the app and sign in with your chosen identity provider.
When you are successfully logged-in, the app should run without errors, and you should be able to query the backend service and make updates to data.
## Cache authentication tokens on the client
The previous example showed a standard sign-in, which requires the client to contact both the identity provider and the backend Azure service every time that the app starts. Not only is this method inefficient, you can run into usage-related issues should many customers try to start you app at the same time. A better approach is to cache the authorization token returned by the Azure service and try to use this first before using a provider-based sign-in.
>[AZURE.NOTE]You can cache the token issued by the backend Azure service regardless of whether you are using client-managed or service-managed authentication. This tutorial uses service-managed authentication.
1. Open the ToDoActivity.java file and add the following import statements:
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
2. Add the the following members to the `ToDoActivity` class.
public static final String SHAREDPREFFILE = "temp";
public static final String USERIDPREF = "uid";
public static final String TOKENPREF = "tkn";
3. In the ToDoActivity.java file, add the the following definition for the `cacheUserToken` method.
private void cacheUserToken(MobileServiceUser user)
{
SharedPreferences prefs = getSharedPreferences(SHAREDPREFFILE, Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putString(USERIDPREF, user.getUserId());
editor.putString(TOKENPREF, user.getAuthenticationToken());
editor.commit();
}
This method stores the user id and token in a preference file that is marked private. This should protect access to the cache so that other apps on the device do not have access to the token because the preference is sandboxed for the app. However, if someone gains access to the device, it is possible that they may gain access to the token cache through other means.
>[AZURE.NOTE]You can further protect the token with encryption if token access to your data is considered highly sensitive and someone may gain access to the device. However, a completely secure solution is beyond the scope of this tutorial and dependent on your security requirements.
4. In the ToDoActivity.java file, add the the following definition for the `loadUserTokenCache` method.
private boolean loadUserTokenCache(MobileServiceClient client)
{
SharedPreferences prefs = getSharedPreferences(SHAREDPREFFILE, Context.MODE_PRIVATE);
String userId = prefs.getString(USERIDPREF, null);
if (userId == null)
return false;
String token = prefs.getString(TOKENPREF, null);
if (token == null)
return false;
MobileServiceUser user = new MobileServiceUser(userId);
user.setAuthenticationToken(token);
client.setCurrentUser(user);
return true;
}
5. In the *ToDoActivity.java* file, replace the `authenticate` method with the following method which uses a token cache. Change the login provider if you want to use an account other than Google.
private void authenticate() {
// We first try to load a token cache if one exists.
if (loadUserTokenCache(mClient))
{
createTable();
}
// If we failed to load a token cache, login and create a token cache
else
{
// Login using the Google provider.
ListenableFuture mLogin = mClient.login(MobileServiceAuthenticationProvider.Google);
Futures.addCallback(mLogin, new FutureCallback() {
@Override
public void onFailure(Throwable exc) {
createAndShowDialog("You must log in. Login Required", "Error");
}
@Override
public void onSuccess(MobileServiceUser user) {
createAndShowDialog(String.format(
"You are now logged in - %1$2s",
user.getUserId()), "Success");
cacheUserToken(mClient.getCurrentUser());
createTable();
}
});
}
}
6. Build the app and test authentication using a valid account. Run it at least twice. During the first run, you should receive a prompt to login and create the token cache. After that, each run will attempt to load the token cache for authentication and you should not be required to login.
## Refresh the token cache
Our token cache should work in a simple case but, what happens when the token expires or is revoked? The token could expire when the app is not running. This would mean the token cache is invalid. The token could also expire while the app is actually running. The result is an HTTP status code 401 "Unauthorized".
We need to be able to detect an expired token, and refresh it. To do this we use a [ServiceFilter](http://dl.windowsazure.com/androiddocs/com/microsoft/windowsazure/mobileservices/ServiceFilter.html) from the [Android client library](http://dl.windowsazure.com/androiddocs/).
In this section you will define a ServiceFilter that will detect a HTTP status code 401 response and trigger a refresh of the token and the token cache. Additionally, this ServiceFilter will block other outbound requests during authentication so that those requests can use the refreshed token.
1. Open the ToDoActivity.java file and add the following import statements:
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.ExecutionException;
import com.microsoft.windowsazure.mobileservices.MobileServiceException;
2. Add the following members to the `ToDoActivity` class.
public boolean bAuthenticating = false;
public final Object mAuthenticationLock = new Object();
These will be used to help synchronize the authentication of the user. We only want to authenticate once. Any calls during an authentication should wait and use the new token from the authentication in progress.
3. In the ToDoActivity.java file, add the following method to the ToDoActivity class that will be used to block outbound calls on other threads while authentication is in progress.
/**
* Detects if authentication is in progress and waits for it to complete.
* Returns true if authentication was detected as in progress. False otherwise.
*/
public boolean detectAndWaitForAuthentication()
{
boolean detected = false;
synchronized(mAuthenticationLock)
{
do
{
if (bAuthenticating == true)
detected = true;
try
{
mAuthenticationLock.wait(1000);
}
catch(InterruptedException e)
{}
}
while(bAuthenticating == true);
}
if (bAuthenticating == true)
return true;
return detected;
}
4. In the ToDoActivity.java file, add the following method to the ToDoActivity class. This method triggers the wait and then update the token on outbound requests when authentication is complete.
/**
* Waits for authentication to complete then adds or updates the token
* in the X-ZUMO-AUTH request header.
*
* @param request
* The request that receives the updated token.
*/
private void waitAndUpdateRequestToken(ServiceFilterRequest request)
{
MobileServiceUser user = null;
if (detectAndWaitForAuthentication())
{
user = mClient.getCurrentUser();
if (user != null)
{
request.removeHeader("X-ZUMO-AUTH");
request.addHeader("X-ZUMO-AUTH", user.getAuthenticationToken());
}
}
}
5. In the ToDoActivity.java file, update the `authenticate` method of the ToDoActivity class so that it accepts a boolean parameter to allow forcing the refresh of the token and token cache. We also need to notify any blocked threads when authentication is completed so they can pick up the new token.
/**
* Authenticates with the desired login provider. Also caches the token.
*
* If a local token cache is detected, the token cache is used instead of an actual
* login unless bRefresh is set to true forcing a refresh.
*
* @param bRefreshCache
* Indicates whether to force a token refresh.
*/
private void authenticate(boolean bRefreshCache) {
bAuthenticating = true;
if (bRefreshCache || !loadUserTokenCache(mClient))
{
// New login using the provider and update the token cache.
mClient.login(MobileServiceAuthenticationProvider.MicrosoftAccount,
new UserAuthenticationCallback() {
@Override
public void onCompleted(MobileServiceUser user,
Exception exception, ServiceFilterResponse response) {
synchronized(mAuthenticationLock)
{
if (exception == null) {
cacheUserToken(mClient.getCurrentUser());
createTable();
} else {
createAndShowDialog(exception.getMessage(), "Login Error");
}
bAuthenticating = false;
mAuthenticationLock.notifyAll();
}
}
});
}
else
{
// Other threads may be blocked waiting to be notified when
// authentication is complete.
synchronized(mAuthenticationLock)
{
bAuthenticating = false;
mAuthenticationLock.notifyAll();
}
createTable();
}
}
6. In the ToDoActivity.java file, add this code for a new `RefreshTokenCacheFilter` class inside the ToDoActivity class:
/**
* The RefreshTokenCacheFilter class filters responses for HTTP status code 401.
* When 401 is encountered, the filter calls the authenticate method on the
* UI thread. Out going requests and retries are blocked during authentication.
* Once authentication is complete, the token cache is updated and
* any blocked request will receive the X-ZUMO-AUTH header added or updated to
* that request.
*/
private class RefreshTokenCacheFilter implements ServiceFilter {
AtomicBoolean mAtomicAuthenticatingFlag = new AtomicBoolean();
@Override
public ListenableFuture handleRequest(
final ServiceFilterRequest request,
final NextServiceFilterCallback nextServiceFilterCallback
)
{
// In this example, if authentication is already in progress we block the request
// until authentication is complete to avoid unnecessary authentications as
// a result of HTTP status code 401.
// If authentication was detected, add the token to the request.
waitAndUpdateRequestToken(request);
// Send the request down the filter chain
// retrying up to 5 times on 401 response codes.
ListenableFuture future = null;
ServiceFilterResponse response = null;
int responseCode = 401;
for (int i = 0; (i < 5 ) && (responseCode == 401); i++)
{
future = nextServiceFilterCallback.onNext(request);
try {
response = future.get();
responseCode = response.getStatus().getStatusCode();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
if (e.getCause().getClass() == MobileServiceException.class)
{
MobileServiceException mEx = (MobileServiceException) e.getCause();
responseCode = mEx.getResponse().getStatus().getStatusCode();
if (responseCode == 401)
{
// Two simultaneous requests from independent threads could get HTTP status 401.
// Protecting against that right here so multiple authentication requests are
// not setup to run on the UI thread.
// We only want to authenticate once. Requests should just wait and retry
// with the new token.
if (mAtomicAuthenticatingFlag.compareAndSet(false, true))
{
// Authenticate on UI thread
runOnUiThread(new Runnable() {
@Override
public void run() {
// Force a token refresh during authentication.
authenticate(true);
}
});
}
// Wait for authentication to complete then update the token in the request.
waitAndUpdateRequestToken(request);
mAtomicAuthenticatingFlag.set(false);
}
}
}
}
return future;
}
}
This service filter will check each response for HTTP status code 401 "Unauthorized". If a 401 is encountered, a new login request to obtain a new token will be setup on the UI thread. Other calls will be blocked until the login is completed, or until 5 attempts have failed. If the new token is obtained, the request that triggered the 401 will be retried with the new token and any blocked calls will be retried with the new token.
7. In the ToDoActivity.java file, add this code for a new `ProgressFilter` class inside the ToDoActivity class:
/**
* The ProgressFilter class renders a progress bar on the screen during the time the App is waiting for the response of a previous request.
* the filter shows the progress bar on the beginning of the request, and hides it when the response arrived.
*/
private class ProgressFilter implements ServiceFilter {
@Override
public ListenableFuture handleRequest(ServiceFilterRequest request, NextServiceFilterCallback nextServiceFilterCallback) {
final SettableFuture resultFuture = SettableFuture.create();
runOnUiThread(new Runnable() {
@Override
public void run() {
if (mProgressBar != null) mProgressBar.setVisibility(ProgressBar.VISIBLE);
}
});
ListenableFuture future = nextServiceFilterCallback.onNext(request);
Futures.addCallback(future, new FutureCallback() {
@Override
public void onFailure(Throwable e) {
resultFuture.setException(e);
}
@Override
public void onSuccess(ServiceFilterResponse response) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (mProgressBar != null) mProgressBar.setVisibility(ProgressBar.GONE);
}
});
resultFuture.set(response);
}
});
return resultFuture;
}
}
This filter will show the progress bar on the beginning of the request and will hide it when the response arrived.
8. In the ToDoActivity.java file, update the `onCreate` method as follows:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_to_do);
mProgressBar = (ProgressBar) findViewById(R.id.loadingProgressBar);
// Initialize the progress bar
mProgressBar.setVisibility(ProgressBar.GONE);
try {
// Create the Mobile Service Client instance, using the provided
// Mobile Service URL and key
mClient = new MobileServiceClient(
"https://.azure-mobile.net/",
"", this)
.withFilter(new ProgressFilter())
.withFilter(new RefreshTokenCacheFilter());
// Authenticate passing false to load the current token cache if available.
authenticate(false);
} catch (MalformedURLException e) {
createAndShowDialog(new Exception("Error creating the Mobile Service. " +
"Verify the URL"), "Error");
}
}
In this code, `RefreshTokenCacheFilter` is used in addition to `ProgressFilter`. Also during `onCreate` we want to load the token cache. So `false` is passed in to the `authenticate` method.
## Next steps
In the next tutorial, [Service-side authorization of Mobile Services users][Authorize users with scripts], you will take the user ID value provided by Mobile Services based on an authenticated user and use it to filter the data returned by Mobile Services.
[Register your app for authentication and configure Mobile Services]: #register
[Restrict table permissions to authenticated users]: #permissions
[Add authentication to the app]: #add-authentication
[Store authentication tokens on the client]: #cache-tokens
[Refresh expired tokens]: #refresh-tokens
[Next Steps]:#next-steps
[Get started with Mobile Services]: mobile-services-dotnet-backend-android-get-started.md
[Get started with authentication]: mobile-services-dotnet-backend-android-get-started-users.md
[Get started with push notifications]: mobile-services-dotnet-backend-android-get-started-push.md
[Authorize users with scripts]: mobile-services-dotnet-backend-service-side-authorization.md
[Mobile Services .NET How-to Conceptual Reference]: https://azure.microsoft.com/develop/mobile/how-to-guides/work-with-net-client-library
[Register your Windows Store app package for Microsoft authentication]: mobile-services-how-to-register-store-app-package-microsoft-authentication.md
================================================
FILE: docs/mobile-services-dotnet-backend-android-get-started.md
================================================
# Get started with Mobile Services
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal JavaScript | Javascript)](mobile-services-javascript-backend-windows-store-javascript-get-started.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started.md)
- [(Android | Javascript)](mobile-services-android-get-started.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started.md)
- [(HTML | Javascript)](mobile-services-html-get-started.md)
- [(PhoneGap | Javascript)](mobile-services-javascript-backend-phonegap-get-started.md)
- [(Sencha | Javascript)](partner-sencha-mobile-services-get-started.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This tutorial shows you how to add a cloud-based backend service to an Android app using Azure Mobile Services. In this tutorial, you will create both a new mobile service and a simple _To do list_ app that stores app data in the new mobile service. The mobile service that you will create uses the supported .NET languages using Visual Studio for server-side business logic and to manage the mobile service. To create a mobile service that lets you write your server-side business logic in JavaScript, see the [JavaScript backend version](mobile-services-android-get-started.md) of this topic.
A screenshot from the completed app is below:

Completing this tutorial requires the [Android Developer Tools][Android Studio], which includes the Android Studio integrated development environment, and the latest Android platform. Android 4.2 or a later version is required.
The downloaded quickstart project contains the Mobile Services SDK for Android.
> [AZURE.IMPORTANT] To complete this tutorial, you need an Azure account. If you don't have an account, you can sign up for an Azure trial and get up to 10 free mobile services that you can keep using even after your trial ends. For details, see [Azure Free Trial](https://azure.microsoft.com/pricing/free-trial/?WT.mc_id=AE564AB28).
## Create a new mobile service
Follow these steps to create a new mobile service.
1. Log into the [Azure classic portal](https://manage.windowsazure.com/). At the bottom of the navigation pane, click **+NEW**. Expand **Compute** and **Mobile Service**, then click **Create**.

This displays the **Create a Mobile Service** dialog.
2. In the **Create a Mobile Service** page, select **Create a free 20 MB SQL Database**, select **.NET** runtime, then type a subdomain name for the new mobile service in the **URL** textbox. Click the right arrow button to go to the next page.

This displays the **Specify database settings** page.
> [AZURE.NOTE] As part of this tutorial, you create a new SQL Database instance and server. You can reuse this new database and administer it as you would any other SQL Database instance. If you already have a database in the same region as the new mobile service, you can instead choose **Use existing Database** and then select that database. The use of a database in a different region is not recommended because of additional bandwidth costs and higher latencies.
3. In **Name**, type the name of the new database, then type **Login name**, which is the administrator login name for the new SQL Database server, type and confirm the password, and click the check button to complete the process.

You have now created a new mobile service that can be used by your mobile apps.
## Download the mobile service to your local computer
Now that you have created the mobile service, download your personalized mobile service project that you can run on your local computer or virtual machine.
1. Click the mobile service that you just created, then in the quickstart tab, click **Android** under **Choose platform** and expand **Create a new Android app**.
![][1]
2. If you haven't already done so, download and install [Visual Studio Professional 2013](https://go.microsoft.com/fwLink/p/?LinkID=391934), or a later version.
3. In Step 2, click **Download** under **Download and publish your service to the cloud**.
This downloads the Visual Studio project that implements your mobile service. Save the compressed project file to your local computer, and make a note of where you saved it.
## Test the mobile service
The mobile service project lets you run your new mobile service locally. This makes it easy to debug your service code before you even publish it to Azure.
1. On your Windows PC, download your personalized server project, extract it, and then open it in Visual Studio.
2. Press the **F5** key to rebuild the project and start the mobile service locally. A web page is displayed after the mobile service starts successfully.
## Publish your mobile service
1. In Visual Studio, right-click the project, click **Publish** > **Microsoft Azure Mobile Services**. Instead of using Visual Studio, [you may also use Git](./
mobile-services-dotnet-backend-store-code-source-control.md).
2. Sign in with Azure credentials and select your service from **Existing Mobile Services**. Visual Studio downloads your publish settings directly from Azure. Finally, click **Publish**.
## Create a new Android app
In this section you will create a new Android app that is connected to your mobile service.
1. In the [Azure classic portal], click **Mobile Services**, and then click the mobile service that you just created.
2. In the quickstart tab, click **Android** under **Choose platform** and expand **Create a new Android app**.
![][2]
3. If you haven't already done so, download and install the [Android Developer Tools][Android SDK] on your local computer or virtual machine.
4. Under **Download and run your app**, click **Download**.
This downloads the project for the sample _To do list_ application that is connected to your mobile service. Save the compressed project file to your local computer, and make a note of where you save it.
## Run your Android app
The final stage of this tutorial is to build and run your new app.
### Load project into Android Studio and sync Gradle
1. Browse to the location where you saved the compressed project files and expand the files on your computer into your Android Studio projects directory.
2. Open Android Studio. If you are working with a project and it appears, close the project (File => Close Project).
3. Select **Open an existing Android Studio project**, browse to the project location, and then click **OK.** This will load the project and start to sync it with Gradle.

4. Wait for the Gradle sync activity to complete. If you see a "failed to find target" error, this is because the version used in Android Studio doesn't match that of the sample. The easiest way to fix this is to click the **Install missing platform(s) and sync project** link in the error message. You might get additional version error messages, and you simply repeat this process until no errors appear.
- There is another way to fix this if you want to run with the "latest and greatest" version of Android. You can update the **targetSdkVersion** in the *build.gradle* file in the *app* directory to match the version already installed on your machine, which you can discover by clicking the **SDK Manager** icon and seeing what version is listed. Next you press the **Sync Project with Gradle Files**. You may get an error message for the version of Build Tools, and you fix that the same way.
### Running the app
You can run the app using the emulator, or using an actual device.
1. To run from a device, connect it to your computer with a USB cable. You must [set up the device for development](https://developer.android.com/training/basics/firstapp/running-app.html). If you are developing on a Windows machine, you must also download and install a USB driver.
2. To run using the Android emulator, you must define at least one Android Virtual Device (AVD). Click the AVD Manager icon to create and manage these devices.
3. From the **Run** menu, click **Run** to start the project. and choose a device or emulator from the dialog box that appears.
4. When the app appears, type meaningful text, such as _Complete the tutorial_, and then click **Add**.

This sends a POST request to the new mobile service hosted in Azure. Data from the request is inserted into the TodoItem table. Items stored in the table are returned by the mobile service, and the data is displayed in the list.
> [AZURE.NOTE] You can review the code that accesses your mobile service to query and insert data, which is found in the ToDoActivity.java file.
8. Back in the Azure classic portal, click the **Data** tab and then click the **TodoItems** table.

This lets you browse the data inserted by the app into the table.

## Next Steps
Now that you have completed the quickstart, learn how to perform additional important tasks in Mobile Services:
* [Add push notifications to your app]
Learn how to send a very basic push notification to your app.
* [Add authentication to your app]
Learn how to restrict access to your backend data to specific registered users of your app.
* [Troubleshoot a Mobile Services .NET backend]
Learn how to diagnose and fix issues that can arise with a Mobile Services .NET backend.
[Getting started with Mobile Services]:#getting-started
[Create a new mobile service]:#create-new-service
[Define the mobile service instance]:#define-mobile-service-instance
[Next Steps]:#next-steps
[0]: ./media/mobile-services-dotnet-backend-android-get-started/mobile-quickstart-completed-android.png
[1]: ./media/mobile-services-dotnet-backend-android-get-started/mobile-quickstart-steps-vs-AS.png
[2]: ./media/mobile-services-dotnet-backend-android-get-started/mobile-quickstart-steps-android-AS.png
[6]: ./media/mobile-services-dotnet-backend-android-get-started/mobile-portal-quickstart-android.png
[7]: ./media/mobile-services-dotnet-backend-android-get-started/mobile-quickstart-steps-android.png
[8]: ./media/mobile-services-dotnet-backend-android-get-started/mobile-eclipse-quickstart.png
[10]: ./media/mobile-services-dotnet-backend-android-get-started/mobile-quickstart-startup-android.png
[11]: ./media/mobile-services-dotnet-backend-android-get-started/mobile-data-tab.png
[12]: ./media/mobile-services-dotnet-backend-android-get-started/mobile-data-browse.png
[14]: ./media/mobile-services-dotnet-backend-android-get-started/mobile-services-import-android-workspace.png
[15]: ./media/mobile-services-dotnet-backend-android-get-started/mobile-services-import-android-project.png
[Get started (Eclipse)]: mobile-services-dotnet-backend-android-get-started-ec.md
[Add push notifications to your app]: mobile-services-dotnet-backend-android-get-started-push.md
[Add authentication to your app]: mobile-services-dotnet-backend-android-get-started-auth.md
[Android SDK]: https://go.microsoft.com/fwLink/p/?LinkID=280125
[Android Studio]: https://developer.android.com/sdk/index.html
[Mobile Services Android SDK]: https://go.microsoft.com/fwLink/p/?LinkID=266533
[Troubleshoot a Mobile Services .NET backend]: mobile-services-dotnet-backend-how-to-troubleshoot.md
[Azure classic portal]: https://manage.windowsazure.com/
================================================
FILE: docs/mobile-services-dotnet-backend-define-custom-api.md
================================================
# How to: define a custom API endpoint in a .NET backend mobile service
> [AZURE.SELECTOR]
- [JavaScript backend](./mobile-services-javascript-backend-define-custom-api.md)
- [.NET backend](./mobile-services-dotnet-backend-define-custom-api.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This topic shows you how to define a custom API endpoint in a .NET backend mobile service. A custom API lets you define custom endpoints with server functionality, but it does not map to a database insert, update, delete, or read operation. By using a custom API, you have more control over messaging, including HTTP headers and body format.
1. In Visual Studio, right-click the Controllers folder, expand **Add**, then click **New Scaffolded Item**. This displays the Add Scaffold dialog.
2. Expand **Azure Mobile Services**, click **Azure Mobile Services Custom Controller**, click **Add**, supply a **Controller name** of `CompleteAllController`, and click **Add** again.

This creates a new empty controller class named **CompleteAllController**.
>[AZURE.NOTE]If your dialog doesn't have Mobile Services-specific scaffolds, instead create a new **Web API Controller - Empty**. In this new controller class, add a public **Services** property, which returns the **ApiServices** type. This property is used to access server-specific settings from inside your controller.
3. In **CompleteAllController.cs**, add the following **using** statements. Replace `todolistService` with the namespace of your mobile service project, which should be the mobile service name appended with `Service`.
using System.Threading.Tasks;
using todolistService.Models;
4. In **CompleteAllController.cs**, add the following class to wrap the response sent to the client.
// We use this class to keep parity with other Mobile Services
// that use the JavaScript backend. This way the same client
// code can call either type of Mobile Service backend.
public class MarkAllResult
{
public int count;
}
5. Add the following code to the new controller. Replace `todolistContext` with the name of the DbContext for your data model, which should be the mobile service name appended with `Context`. Similarly, replace the schema name in the UPDATE statement with the name of your mobile service. This code uses the [Database Class](http://msdn.microsoft.com/library/system.data.entity.database.aspx) to access the **TodoItems** table directly to set the completed flag on all items. This method supports a POST request, and the number of changed rows is returned to the client as an integer value.
// POST api/completeall
public async Task Post()
{
using (todolistContext context = new todolistContext())
{
// Get the database from the context.
var database = context.Database;
// Create a SQL statement that sets all uncompleted items
// to complete and execute the statement asynchronously.
var sql = @"UPDATE todolist.TodoItems SET Complete = 1 " +
@"WHERE Complete = 0; SELECT @@ROWCOUNT as count";
var result = new MarkAllResult();
result.count = await database.ExecuteSqlCommandAsync(sql);
// Log the result.
Services.Log.Info(string.Format("{0} items set to 'complete'.",
result.count.ToString()));
return result;
}
}
> [AZURE.TIP] With default permissions, anyone with the app key may call the custom API. However, the application key is not considered a secure credential because it may not be distributed or stored securely. Consider restricting access to only authenticated users for additional security.
For information on how to invoke a custom API in your app using a Mobile Services client library, see [Call a custom API](mobile-services-windows-dotnet-how-to-use-client-library.md#custom-api) in the client SDK reference.
================================================
FILE: docs/mobile-services-dotnet-backend-get-started-custom-authentication.md
================================================
# Get started with custom authentication
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
## Overview
This topic shows you how to authenticate users in the Azure Mobile Services .NET backend by issuing your own Mobile Services authentication token. In this tutorial, you add authentication to the quickstart project using a custom username and password for your app.
>[AZURE.NOTE] This tutorial demonstrates an advanced method of authenticating your Mobile Services with custom credentials. Many apps will be best suited to instead use the built-in social identity providers, allowing users to log in via Facebook, Twitter, Google, Microsoft Account, and Azure Active Directory. If this is your first experience with authentication in Mobile Services, please see the [Add authentication to your app] tutorial.
This tutorial is based on the Mobile Services quickstart. You must also first complete the tutorial [Get started with Mobile Services].
>[AZURE.IMPORTANT] The purpose of this tutorial is to show you how to issue an authentication token for Mobile Services. This is not to be taken as security guidance. In developing your app, you need to be aware of the security implications of password storage, and you need to have a strategy for managing brute-force attacks.
## Set up the accounts table
Because you are using custom authentication and not relying on another identity provider, you will need to store your users' sign-in information. In this section, you will create a table for your accounts and set up the basic security mechanisms. The accounts table will contain the usernames and the salted and hashed passwords, and you can also include additional user information if needed.
1. In the **DataObjects** folder of your backend project, add a new entity called `Account`.
2. Add the following `using` statement:
using Microsoft.WindowsAzure.Mobile.Service;
3. Replace the class definition with the following code:
public class Account : EntityData
{
public string Username { get; set; }
public byte[] Salt { get; set; }
public byte[] SaltedAndHashedPassword { get; set; }
}
This represents a row in a new Account table, which contains the username, that user's salt, and the securly stored password.
2. Under the **Models** folder, you will find a **DbContext** derived class named after your mobile service. Open your context and add the accounts table to your data model by including the following:
public DbSet Accounts { get; set; }
>[AZURE.NOTE]The code snippets in this tutorial use `todoContext` as the context name. You must update the code snippets for your project's context.
Next, you will set up the security functions for working with this data.
5. Create a class called `CustomLoginProviderUtils` and add the following `using` statement:
using System.Security.Cryptography;
6. Add the following code methods to the new class:
public static byte[] hash(string plaintext, byte[] salt)
{
SHA512Cng hashFunc = new SHA512Cng();
byte[] plainBytes = System.Text.Encoding.ASCII.GetBytes(plaintext);
byte[] toHash = new byte[plainBytes.Length + salt.Length];
plainBytes.CopyTo(toHash,0);
salt.CopyTo(toHash, plainBytes.Length);
return hashFunc.ComputeHash(toHash);
}
public static byte[] generateSalt()
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] salt = new byte[256];
rng.GetBytes(salt);
return salt;
}
public static bool slowEquals(byte[] a, byte[] b)
{
int diff = a.Length ^ b.Length;
for (int i = 0; i < a.Length && i < b.Length; i++)
{
diff |= a[i] ^ b[i];
}
return diff == 0;
}
This lets you generate a new long salt, adds the ability to hash a salted password, and provides a secure way of comparing two hashes.
## Create the registration endpoint
At this point, you have everything you need to begin creating user accounts. In this section, you will set up a registration endpoint to handle new registration requests. This is where you will enforce new username and password policies and ensure that the username is not taken. Then you will safely store the user information in your database.
1. Create the following new class to represent an incoming registration attempt:
public class RegistrationRequest
{
public String username { get; set; }
public String password { get; set; }
}
If you need to collect and store other information during registration, you should do it here.
2. In your mobile service backend project, right-click **Controllers**, click **Add** and **Controller**, create a new **Microsoft Azure Mobile Services Custom Controller** named `CustomRegistrationController`, then add the following `using` statements:
using Microsoft.WindowsAzure.Mobile.Service.Security;
using System.Text.RegularExpressions;
using .DataObjects;
using .Models;
In the above code, replace the placeholder with your project's namespace.
4. Replace the class definition with the following code:
[AuthorizeLevel(AuthorizationLevel.Anonymous)]
public class CustomRegistrationController : ApiController
{
public ApiServices Services { get; set; }
// POST api/CustomRegistration
public HttpResponseMessage Post(RegistrationRequest registrationRequest)
{
if (!Regex.IsMatch(registrationRequest.username, "^[a-zA-Z0-9]{4,}$"))
{
return this.Request.CreateResponse(HttpStatusCode.BadRequest, "Invalid username (at least 4 chars, alphanumeric only)");
}
else if (registrationRequest.password.Length < 8)
{
return this.Request.CreateResponse(HttpStatusCode.BadRequest, "Invalid password (at least 8 chars required)");
}
todoContext context = new todoContext();
Account account = context.Accounts.Where(a => a.Username == registrationRequest.username).SingleOrDefault();
if (account != null)
{
return this.Request.CreateResponse(HttpStatusCode.BadRequest, "That username already exists.");
}
else
{
byte[] salt = CustomLoginProviderUtils.generateSalt();
Account newAccount = new Account
{
Id = Guid.NewGuid().ToString(),
Username = registrationRequest.username,
Salt = salt,
SaltedAndHashedPassword = CustomLoginProviderUtils.hash(registrationRequest.password, salt)
};
context.Accounts.Add(newAccount);
context.SaveChanges();
return this.Request.CreateResponse(HttpStatusCode.Created);
}
}
}
Remember to replace the *todoContext* variable with the name of your project's **DbContext**. Note that this controller uses the following attribute to allow all traffic to this endpoint:
[AuthorizeLevel(AuthorizationLevel.Anonymous)]
>[AZURE.IMPORTANT]This registration endpoint can be accessed by any client via HTTP. Before you publish this service to a production environment, you should implement some sort of scheme to validate registrations, such as a SMS or email-based verification. This can help prevent a malicious user from creating fraudulent registrations.
## Create the LoginProvider
One of the fundamental constructs in the Mobile Services authentication pipeline is the **LoginProvider**. In this section, you will create your own `CustomLoginProvider`. It will not be plugged into the pipeline like the built-in providers, but it will provide you with some convenient functionality.
If you use the visual studio 2013, you maybe need to install the `WindowsAzure.MobileServices.Backend.Security` nuget package to add the references to `LoginProvider` class.
1. Create a new class, `CustomLoginProvider`, which derives from **LoginProvider**, and add the following `using` statements:
using Microsoft.WindowsAzure.Mobile.Service;
using Microsoft.WindowsAzure.Mobile.Service.Security;
using Newtonsoft.Json.Linq;
using Owin;
using System.Security.Claims;
3. replace the **CustomLoginProvider** class definition with the following code:
public class CustomLoginProvider : LoginProvider
{
public const string ProviderName = "custom";
public override string Name
{
get { return ProviderName; }
}
public CustomLoginProvider(IServiceTokenHandler tokenHandler)
: base(tokenHandler)
{
this.TokenLifetime = new TimeSpan(30, 0, 0, 0);
}
}
If you try to build the project now it will fail. `LoginProvider` has three abstract methods that you need to implement, which you will do later.
2. Create a new class named `CustomLoginProviderCredentials` in the same code file.
public class CustomLoginProviderCredentials : ProviderCredentials
{
public CustomLoginProviderCredentials()
: base(CustomLoginProvider.ProviderName)
{
}
}
This represents information about your user and will be made available to you on the backend via [GetIdentitiesAsync](https://msdn.microsoft.com/library/azure/microsoft.windowsazure.mobile.service.security.serviceuser.getidentitiesasync.aspx). If you are adding custom claims, make sure that they are captured in this object.
3. Add the following implementation of the abstract method `ConfigureMiddleware` to **CustomLoginProvider**.
public override void ConfigureMiddleware(IAppBuilder appBuilder, ServiceSettingsDictionary settings)
{
// Not Applicable - used for federated identity flows
return;
}
This method is not implemented because **CustomLoginProvider** is not integrating with the authentication pipeline.
4. Add the following implementation of the abstract method `ParseCredentials` to **CustomLoginProvider**.
public override ProviderCredentials ParseCredentials(JObject serialized)
{
if (serialized == null)
{
throw new ArgumentNullException("serialized");
}
return serialized.ToObject();
}
This method will allow the backend to deserialize user information from an incoming authentication token.
5. Add the following implementation of the abstract method `CreateCredentials` to **CustomLoginProvider**.
public override ProviderCredentials CreateCredentials(ClaimsIdentity claimsIdentity)
{
if (claimsIdentity == null)
{
throw new ArgumentNullException("claimsIdentity");
}
string username = claimsIdentity.FindFirst(ClaimTypes.NameIdentifier).Value;
CustomLoginProviderCredentials credentials = new CustomLoginProviderCredentials
{
UserId = this.TokenHandler.CreateUserId(this.Name, username)
};
return credentials;
}
This method translates a [ClaimsIdentity] into a [ProviderCredentials] object that is used in the authentication token issuance phase. You will again want to capture any additional claims in this method.
6. Open the WebApiConfig.cs project file in the App_Start folder and the following line of code after the **ConfigOptions** is created:
options.LoginProviders.Add(typeof(CustomLoginProvider));
## Create the sign-in endpoint
Next, you create an endpoint for your users to sign-in. The username and password that you receive is checked against the database by first applying the user's salt, hashing the password, and making sure that the incoming value matches that of the database. If it does, then you can create a [ClaimsIdentity] and pass it to the **CustomLoginProvider**. The client app receives a user ID and an authentication token for further access to your mobile service.
1. In your mobile service backend project, create the following new `LoginRequest` class:
public class LoginRequest
{
public String username { get; set; }
public String password { get; set; }
}
This class represents an incoming sign-in attempt.
2. Create the following new `CustomLoginResult` class:
public class CustomLoginResult
{
public string UserId { get; set; }
public string MobileServiceAuthenticationToken { get; set; }
}
This class represents a successful login with the user ID and the authentication token. Note that this class has the same shape as the MobileServiceUser class on the client, which makes it easier to hand the login response on a strongly-typed client.
2. Right-click **Controllers**, click **Add** and **Controller**, create a new **Microsoft Azure Mobile Services Custom Controller** named `CustomLoginController`, then add the following `using` statements:
using Microsoft.WindowsAzure.Mobile.Service.Security;
using System.Security.Claims;
using .DataObjects;
using .Models;
3. Replace the **CustomLoginController** class definition with following code:
[AuthorizeLevel(AuthorizationLevel.Anonymous)]
public class CustomLoginController : ApiController
{
public ApiServices Services { get; set; }
public IServiceTokenHandler handler { get; set; }
// POST api/CustomLogin
public HttpResponseMessage Post(LoginRequest loginRequest)
{
todoContext context = new todoContext();
Account account = context.Accounts
.Where(a => a.Username == loginRequest.username).SingleOrDefault();
if (account != null)
{
byte[] incoming = CustomLoginProviderUtils
.hash(loginRequest.password, account.Salt);
if (CustomLoginProviderUtils.slowEquals(incoming, account.SaltedAndHashedPassword))
{
ClaimsIdentity claimsIdentity = new ClaimsIdentity();
claimsIdentity.AddClaim(new Claim(ClaimTypes.NameIdentifier, loginRequest.username));
LoginResult loginResult = new CustomLoginProvider(handler)
.CreateLoginResult(claimsIdentity, Services.Settings.MasterKey);
var customLoginResult = new CustomLoginResult()
{
UserId = loginResult.User.UserId,
MobileServiceAuthenticationToken = loginResult.AuthenticationToken
};
return this.Request.CreateResponse(HttpStatusCode.OK, customLoginResult);
}
}
return this.Request.CreateResponse(HttpStatusCode.Unauthorized,
"Invalid username or password");
}
}
Remember to replace the *todoContext* variable with the name of your project's **DbContext**. Note that this controller uses the following attribute to allow all traffic to this endpoint:
[AuthorizeLevel(AuthorizationLevel.Anonymous)]
>[AZURE.IMPORTANT] Your `CustomLoginController` for production use should also contain a brute-force detection strategy. Otherwise your sign-in solution may be vulnerable to attack.
## Configure the mobile service to require authentication
By default, all requests to mobile service resources are restricted to clients that present the application key, which does not strictly secure access to resources. To secure your resources, you must restrict access to only authenticated clients.
1. In Visual Studio, open your mobile service project, expand the Controllers folder, and open **TodoItemController.cs**. The **TodoItemController** class implements data access for the TodoItem table. Add the following `using` statement:
using Microsoft.WindowsAzure.Mobile.Service.Security;
2. Apply the following _AuthorizeLevel_ attribute to the **TodoItemController** class.
[AuthorizeLevel(AuthorizationLevel.User)]
This makes sure that all operations against the _TodoItem_ table require an authenticated user. You can also apply the *AuthorizeLevel* attribute at the method level.
3. (Optional) If you wish to debug authentication locally, expand the `App_Start` folder, open **WebApiConfig.cs**, and add the following code to the **Register** method.
config.SetIsHosted(true);
This tells the local mobile service project to run as if it is being hosted in Azure, including honoring the *AuthorizeLevel* settings. Without this setting, all HTTP requests to localhost are permitted without authentication despite the *AuthorizeLevel* setting. When you enable self-hosted mode, you also need to set a value for the local application key.
4. (Optional) In the web.config project file, set a string value for the `MS_ApplicationKey` app setting.
This is the password that you use (with no username) to test the API help pages when you run the service locally. This string value is not used by the live site in Azure, and you do not need to use the actual application key; any valid string value will work.
4. Republish your project.
## Test the sign-in flow using the test client
In your client app, you must develop a custom sign-in screen which takes usernames and passwords and sends them as a JSON payload to your registration and sign-in endpoints. To complete this tutorial, you will instead just use the built-in test client for the Mobile Services .NET backend.
1. In Visual Studio, right-click the mobile service project, then click **Debug** and **Start New Instance**.
This starts a new debugging instance of your mobile service backend project. After the service starts successfully, you will see a start page that says **This mobile service is up and running**.
2. On the service start page, click **Try it out**, then type the password that you set for the **MS_ApplicationKey** app setting in the web.config file with a blank username into the authentication dialog.
3. In the help page, click the **CustomRegistration** endpoint, then click **Try this out**.
![][2]
4. In the body, replace the sample strings with a username and password, which meet the criteria you specified before, then click **Send**.
![][3]
The response should be **201/Created**.
5. Click the browser's back button and repeat steps 2 and 3 for the **CustomLogin** endpoint, using the same username and password that you registered in the previous step.
![][4]
You should receive response message with a body that contains a **user** JSON object that has both the *userId* and an *authenticationToken*, which is the Mobile Services authentication token generated by your custom authentication. This token is sufficient to grant the client app access to the TodoItem endpoint.
Make a copy of the *authenticationToken* value. You will use this to access the restricted TodoItem endpoint.
6. Click the browser's back button, then in the API documentation page, click **GetTables**, click **Try this out**.
7. In the GET request dialog, click the plus sign next to **Headers**, type the value `X-ZUMO-AUTH` in the left box, paste the copied *authenticationToken* value in the right box, then click **Send**.

The mobile service should grant access to the endpoint and return a **200/OK** status along with a list of TodoItems in the table.

>[AZURE.IMPORTANT] If you choose to also publish this mobile service project to Azure for testing, remember that your sign-in and authentication providers will be vulnerable to attack. Make sure that they are either hardened appropriately or that the test data being protected is not important to you. Take great caution before using a custom authentication scheme to secure a production service.
## Sign in using custom authentication from the client
This section describes the steps needed to access the custom authentication endpoints from the client to obtain the authentication token needed to access the mobile service. Because the specific client code you need depends on your client, the guidance provided here is platform agnostic.
>[AZURE.NOTE] The Mobile Services client libraries communicate with the service over HTTPS. Because this solution requires you to send passwords as plaintext, you must make sure that you use HTTPS when you call these endpoint using direct REST requests.
1. Create the required UI elements in your client app to allow users to enter a username and password.
2. Use the appropriate **invokeApi** method on the **MobileServiceClient** in the client library to call the **CustomRegistration** endpoint, passing the runtime-supplied username and password in the message body.
You only need to call the **CustomRegistration** endpoint once to create an account for a given user, as long as you keep the user login information in the Accounts table. For examples of how to call a custom API on the various supported client platforms, see the article [Custom API in Azure Mobile Services ??? client SDKs](http://blogs.msdn.com/b/carlosfigueira/archive/2013/06/19/custom-api-in-azure-mobile-services-client-sdks.aspx).
> [AZURE.IMPORTANT] Because this user provisioning step occurs only once, you should consider creating the user account in some out-of-band fashion. For a public registration endpoint, you should also consider implementing an SMS-based or email-based verification process, or some other safeguard to prevent the generation of fruadulent accounts. You can use Twilio to send SMS messages from Mobile services. You can also use SendGrid to send emails from Mobile Services. For more inforation on using SendGrid, see [Send email from Mobile Services with SendGrid](store-sendgrid-mobile-services-send-email-scripts.md).
3. Use the appropriate **invokeApi** method again, this time to call the **CustomLogin** endpoint, passing the runtime-supplied username and password in the message body.
This time, you must capture the *userId* and *authenticationToken* values returned in the response object after a successful login.
4. Use the returned *userId* and *authenticationToken* values to create a new **MobileServiceUser** object and set it as the current user for your **MobileServiceClient** instance, as shown in the topic [Add authentication to existing app](mobile-services-dotnet-backend-ios-get-started-users.md). Because the CustomLogin result is the same shape as the **MobileServiceUser** object, you should be able to make a direct cast of the result.
This completes this tutorial.
[0]: ./media/mobile-services-dotnet-backend-get-started-custom-authentication/mobile-services-dotnet-backend-debug-start.png
[1]: ./media/mobile-services-dotnet-backend-get-started-custom-authentication/mobile-services-dotnet-backend-try-out.png
[2]: ./media/mobile-services-dotnet-backend-get-started-custom-authentication/mobile-services-dotnet-backend-custom-auth-test-client.png
[3]: ./media/mobile-services-dotnet-backend-get-started-custom-authentication/mobile-services-dotnet-backend-custom-auth-send-register.png
[4]: ./media/mobile-services-dotnet-backend-get-started-custom-authentication/mobile-services-dotnet-backend-custom-auth-login-result.png
[Add authentication to your app]: mobile-services-dotnet-backend-windows-store-dotnet-get-started-users.md
[Get started with Mobile Services]: mobile-services-dotnet-backend-windows-store-dotnet-get-started.md
[ClaimsIdentity]: https://msdn.microsoft.com/library/system.security.claims.claimsidentity(v=vs.110).aspx
[ProviderCredentials]: https://msdn.microsoft.com/library/azure/microsoft.windowsazure.mobile.service.security.providercredentials.aspx
================================================
FILE: docs/mobile-services-dotnet-backend-how-to-configure-iis-express.md
================================================
# Configure the local web server to allow connections to a local mobile service
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
Azure Mobile Services enables you create your mobile service in Visual Studio using one of the supported .NET languages and then publish it to Azure. One of the major benefits of using a .NET backend for your mobile service is the ability to run, test, and debug the mobile service on your local computer or virtual machine before publishing it to Azure.
To be able to test a mobile service locally with clients running on an emulator, virtual machine or on a separate workstation, you have to configure the local Web server and host computer to allow connections to the workstation's IP address and port. This topic shows you how to configure IIS Express to enable connections to your locally hosted mobile service.
1. Make sure to stop the mobile service if it is currently running in IIS Express. Right click the IIS Express tray icon and click **stop** for the mobile service.

2. In a command prompt window, run the **ipconfig** command to look up a valid local IP address for your workstation.

3. In Visual Studio, open the applicationhost.config file for IIS Express. This file is located in the following subdirectory of your user profile directory.
C:\Users\\Documents\IISExpress\config\applicationhost.config
4. Configure IIS Express to allow remote connection requests to the service. To do this, in the applicationhost.config file, find the site element for your mobile service and add a new `binding` element for the port using the IP address you noted above. Then save the applicationhost.config file.
Your updated site element should look similar to the following:
5. Open the Windows Firewall console and create a new port rule to allow connections to the port. For more information on creating a new Windows Firewall port rule, see [How to add a new Windows Firewall port rule].
>[AZURE.NOTE] If your test machine is joined to a domain, firewall exceptions may be controlled by a domain policy. In this case, you would need to contact your domain adminstrator to get an exemption for the port on your machine.
You should now be configured to test with IIS Express hosting your mobile service.
>[AZURE.NOTE] Once you finish your testing of the service locally, you should delete the Windows Firewall rule you created.
[How to add a new Windows Firewall port rule]: http://go.microsoft.com/fwlink/?LinkId=392240
================================================
FILE: docs/mobile-services-dotnet-backend-how-to-troubleshoot.md
================================================
# Troubleshoot the Mobile Services .NET Backend
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
Developing with Mobile Services is usually easy and painless, but even then things can sometimes go wrong. This tutorial covers some techniques that let you troubleshoot common problems that can arise with the Mobile Services .NET backend.
1. [HTTP Debugging](#HttpDebugging)
2. [Runtime Debugging](#RuntimeDebugging)
3. [Analyzing Diagnostic Logs](#Logs)
4. [Debugging Cloud Assembly Resolution](#AssemblyResolution)
5. [Troubleshooting Entity Framework Migrations](#EFMigrations)
## HTTP Debugging
When developing apps with Mobile Services, you usually take advantage of the Mobile Services client SDK for the platform you are using (Windows Store, iOS, Android, etc). However some times it is helpful to drop down to the HTTP level and observe the raw calls as they happen on the network. This approach is particularly useful when debugging connectivity and serialization issues. With the Mobile Services .NET backend you can use this approach in combination with Visual Studio local and remote debugging (more on that in the next section) to get a complete idea of the the path a HTTP call makes before it invokes your service code.
You can use any HTTP debugger to send and inspect HTTP traffic. [Fiddler](http://www.telerik.com/fiddler) is a popular tool commonly used by developers for this purpose. To make developers' lives easier, Mobile Services bundles a web-based HTTP debugger (also referred to as the "test client) right with your mobile service, reducing the need for external tooling. When hosting your mobile service locally, it will be available at a URI similar to `http://localhost:59233` and when hosting in the cloud, the URI will be of the form `http://todo-list.azure-mobile.net`. The following steps work the same way regardless of where the service is hosted:
1. Start with a Mobile Services server project open in **Visual Studio 2013 Update 2** or later. If you don't have one handy, you can create one by selecting **File**, **New**, **Project**, then selecting the **Cloud** node and then the **Microsoft Azure Mobile Services** template.
2. Hit **F5**, which will build and run the project. On the start page, select **try it out**.
>[AZURE.NOTE]
> If the service is hosted locally, clicking the link will direct you to the next page. However, if hosting in the cloud, you will be prompted for a set of credentials. This is to ensure that unauthenticated users don't have access to information about your API and payloads. In order to see the page, you need to log in with a **blank username** and your **application key** as the password. Your application key is available in the Azure classic portal by navigating to the **Dashboard** tab for your mobile service and selecting **Manage keys**.
>
> ![Authentication prompt to access help page][HelpPageAuth]
3. The page you see (referred to as the "help page") shows a list of all HTTP APIs that your mobile service is making available. Select one of the APIs (if you started using the Mobile Services project template in Visual Studio, you should see **GET tables/TodoItem**).
![Help page][HelpPage]
4. The resulting page shows any documentation and JSON examples of the request and response that the API expects. Select the **try this out** button.
![Test page for an API][HelpPageApi]
5. This is the "test client", which lets you send a HTTP request to try out your API. Select **send**.
![Test client][TestClient]
6. You will see the HTTP response coming back from your mobile service right in the browser window.
![Test client with HTTP response][TestClientResponse]
Now you are ready to explore the different HTTP APIs exposed by your mobile service in the convenience of your web browser.
## Runtime Debugging
One of the key features of the .NET backend is the ability to debug the service code locally, but also to debug the code running live in the cloud environment. Follow these steps:
1. Open the mobile service project you would like to debug in **Visual Studio 2013 Update 2** or later.
2. Configure symbol loading. Navigate to the **Debug** menu and select **Options and Settings**. Ensure that **Enable Just My Code** is unchecked and that **Enable source server support** is checked.
![Configure symbol loading][SymbolLoading]
3. Select the **Symbols** node on the left and add a reference to the [SymbolSource] server using the URI `http://srv.symbolsource.org/pdb/Public`. Symbols for the Mobile Services .NET backend are made available there with every new release.
![Configure symbol server][SymbolServer]
4. Set a breakpoint in the piece of code you would like to debug. For example set a breakpoint in the **GetAllTodoItems()** method of the **TodoItemController** that comes with the Mobile Services project template in Visual Studio.
5. Debug the service locally by pressing **F5**. The first load may be slow as Visual Studio is downloading symbols for the Mobile Services .NET backend.
6. As described in the previous section on HTTP debugging, use the test client to send a HTTP request to the method where you set the breakpoint. For example you can send a request to the **GetAllTodoItems()** method by selecting **GET tables/TodoItem** on the help page, then selecting **try this out** and then **send**.
7. Visual Studio should break at the breakpoint you set, and a full stack trace with source code should be available in the **Call Stack** window in Visual Studio.
![Hitting a breakpoint][Breakpoint]
8. You can now publish the service to Azure, and we will be able to use debugging just like we did above. Publish the project by right-clicking it in **Solution Explorer** and selecting **Publish**.
9. On the **Settings** tab of the Publish wizard, select the **Debug** configuration. This ensures that the relevant debugging symbols are published with your code.
![Publish debug][PublishDebug]
10. Once the service has published successfully, open **Server Explorer** and expand the **Azure** and **Mobile Services** nodes. Sign in if necessary.
11. Right click the mobile service you just published to and select **Attach Debugger**.
![Attach debugger][AttachDebugger]
12. Just as you did in step 6, send a HTTP request to invoke the method where you set the breakpoint. This time use the help page and test client for the Azure-hosted mobile service.
13. Visual Studio will break at the breakpoint.
You now have access the the full power of the Visual Studio debugger when developing locally and against your live mobile service in Azure.
## Analyzing Diagnostic Logs
As your mobile service handles requests from your customers, it generates a variety of useful diagnostic information, and also captures any exceptions encountered. In addition to that, you can instrument your controller code with additional logs by taking advantage of the [**Log**](http://msdn.microsoft.com/library/microsoft.windowsazure.mobile.service.apiservices.log.aspx) property available on the [**Services**](http://msdn.microsoft.com/library/microsoft.windowsazure.mobile.service.tables.tablecontroller.services.aspx) property of every [**TableController**](http://msdn.microsoft.com/library/microsoft.windowsazure.mobile.service.tables.tablecontroller.aspx).
When debugging locally, the logs will appear in the Visual Studio **Output** window.
![Logs in Visual Studio Output window][LogsOutputWindow]
After you publish your service to Azure, the logs for the service instance running in the cloud are available by right-clicking the mobile service in Visual Studio's **Server Explorer** and then selecting **View Logs**.
![Logs in Visual Studio Server Explorer][LogsServerExplorer]
The same logs are also available in the Azure classic portal on the **Logs** tab for your mobile service.
![Logs in Azure classic portal][LogsPortal]
## Debugging Cloud Assembly Resolution
When you publish your mobile service to Azure, it gets loaded by the Mobile Services hosting environment, which ensures seamless upgrades and patches to the HTTP pipeline hosting your controller code. This includes all assemblies referenced by the [.NET backend NuGet packages](http://www.nuget.org/packages?q=%22mobile+services+.net+backend%22): the team constantly updates the service to use the latest versions of those assemblies.
It is sometimes possible to introduce versioning conflicts by referencing *different major versions* of required assemblies (different *minor* versions are allowed). Frequently this happens when NuGet prompts you to upgrade to the latest version of one of the packages used by the Mobile Services .NET backend.
>[AZURE.NOTE] Mobile Services is currently compatible only with ASP.NET 5.1; ASP.NET 5.2 is not presently supported. Upgrading your ASP.NET NuGet packages to 5.2.* may result in an error after deployment.
If you do upgrade any such packages, when you publish the updated service to Azure, you will see a warning page indicating the conflict:
![Help page indicating assembly loading conflict][HelpConflict]
This will be accompanied by an exception message similar to the following being recored in your service logs:
Found conflicts between different versions of the same dependent assembly 'Microsoft.ServiceBus': 2.2.0.0, 2.3.0.0. Please change your project to use version '2.2.0.0' which is the one currently supported by the hosting environment.
This problem is easy to correct: simply revert to a supported version of the required assembly and republish your service.
## Troubleshooting Entity Framework Migrations
When using the Mobile Services .NET backend with a SQL Database, Entity Framework (EF) is used as the data access technology that enables you to query the database and persist objects into it. One important aspect that EF handles on behalf of the developer is how the database columns (also known as *schema*) change as the model classes specified in code change. This process is known as [Code First Migrations](http://msdn.microsoft.com/data/jj591621).
Migrations can be complex and require that the database state be kept in sync with the EF model in order to succeed. For instructions on how to handle migrations with you mobile service and errors that can arise, see [How to make data model changes to a .NET backend mobile service](mobile-services-dotnet-backend-how-to-use-code-first-migrations.md).
[HelpPageAuth]: ./media/mobile-services-dotnet-backend-how-to-troubleshoot/6.png
[HelpPage]: ./media/mobile-services-dotnet-backend-how-to-troubleshoot/7.png
[HelpPageApi]: ./media/mobile-services-dotnet-backend-how-to-troubleshoot/8.png
[TestClient]: ./media/mobile-services-dotnet-backend-how-to-troubleshoot/9.png
[TestClientResponse]: ./media/mobile-services-dotnet-backend-how-to-troubleshoot/10.png
[SymbolLoading]: ./media/mobile-services-dotnet-backend-how-to-troubleshoot/1.png
[SymbolServer]: ./media/mobile-services-dotnet-backend-how-to-troubleshoot/2.png
[Breakpoint]: ./media/mobile-services-dotnet-backend-how-to-troubleshoot/3.png
[PublishDebug]: ./media/mobile-services-dotnet-backend-how-to-troubleshoot/4.png
[AttachDebugger]: ./media/mobile-services-dotnet-backend-how-to-troubleshoot/5.png
[LogsOutputWindow]: ./media/mobile-services-dotnet-backend-how-to-troubleshoot/11.png
[LogsServerExplorer]: ./media/mobile-services-dotnet-backend-how-to-troubleshoot/12.png
[LogsPortal]: ./media/mobile-services-dotnet-backend-how-to-troubleshoot/13.png
[HelpConflict]: ./media/mobile-services-dotnet-backend-how-to-troubleshoot/14.png
[SymbolSource]:http://www.symbolsource.org/Public
================================================
FILE: docs/mobile-services-dotnet-backend-how-to-use-code-first-migrations.md
================================================
# How to make data model changes to a .NET backend mobile service
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This topic shows how to use Code First Migrations in Entity Framework to make data model changes to an existing Azure SQL Database to avoid losing existing data. This procedure assumes that you have already published your .NET backend project to Azure, that there is existing data in your database, and that the remote and local data models are still in sync. This topic also describes the default Code First initializers implemented by Azure Mobile Services that are used during development. These initializers let you easily make schema changes without using Code First Migrations when it is not necessary to maintain you existing data.
>[AZURE.NOTE]The schema name that is used to prefix your tables in the SQL Database is defined by the MS_MobileServiceName app setting in the web.config file. When you download the starter project from the portal, this value is already set to the mobile service name. When your schema name matches the mobile service, multiple mobile services can safely share the same database instance.
Note that automatic migrations are not supported in a .NET backend project.
## Updating the data model
As you add functionality to your .NET backend mobile service, you add new controllers to expose new endpoints in your API. You create a new API as either a custom controller or a table controller. A [TableController] exposes a data type that inherits from [EntityData]. To enable data to be persisted to the database, this data type must also be added to the data model as a new [DbSet] in the [DbContext]. To learn more about Code First in the Entity Framework, see [Creating a Model with Code First](https://msdn.microsoft.com/data/ee712907#codefirst).
Visual Studio makes it easy to create a new table controller to expose a new data type to client apps. For more information, see [How to use controllers to access data in mobile services](https://msdn.microsoft.com/library/windows/apps/xaml/dn614132.aspx).
## Data model initializers
Mobile Services provides two data model initializer base classes in a .NET backend mobile service project. Both initializers drop and recreate tables in the database when the Entity Framework detects a data model change in your [DbContext]. These initializers are designed to work both when you mobile service is running on a local computer and when it is hosted in Azure.
>[AZURE.NOTE]When you publish a .NET backend mobile service, the initializer is not run until a data access operation occurs. This means that for a newly published service, the data tables used for storage aren't created until a data access operation, such as a query, is requested by the client.
>
>You can also execute a data access operation by using the built-in API help functionality, accessed from the **Try it out** link on the start page. For more information on using the API pages to test your mobile service, see the section Test the mobile service project locally in [Add Mobile Services to an existing app](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-data.md#test-the-service-locally).
Both initializers delete from the database all tables, views, functions, and procedures in the schema used by the mobile service.
+ **ClearDatabaseSchemaIfModelChanges** Schema objects are deleted only when Code First detects a change in the data model. The default initializer in a .NET backend project downloaded from the [Azure classic portal] inherits from this base class.
+ **ClearDatabaseSchemaAlways**: Schema objects are deleted every time that the data model is accessed. Use this base class to reset the database without having to make a data model change.
You can use other Code First data model initializers when running on a local computer. However, initializers that attempt to drop the database will fail in Azure because the user does not have permissions to drop the database, which is a good thing.
You may continue to use initializers during local development of your mobile service, and the .NET backend tutorials assume that you are using initializers. However, for situations where you want to make data model changes and maintain existing data in the database, you must use Code First Migrations.
>[AZURE.IMPORTANT]When developing and testing your mobile service project against live Azure services, you should always use a mobile service instance that is dedicated for testing. You should never develop or test against a mobile service that is currently in production or being used by client apps.
In the downloaded quickstart project, the Code First initializer is defined in the WebApiConfig.cs file. Override the **Seed** method to add initial rows of data to new tables. For examples of seeding data, see [Seeding data in migrations].
## Enable Code First Migrations
Code First Migrations uses a snapshot method to generate code that, when executed, makes schema changes to the database. With Migrations, you can make incremental changes to your data model and maintain existing data in the database.
>[AZURE.NOTE]If you have already published your .NET backend mobile service project to Azure, and your SQL Database table schema does not match the current data model of your project, you must use an initializer, drop the tables manually, or otherwise get the schema and data model in sync before you try to publish using Code First Migrations.
The following steps turn on Migrations and apply data model changes in the project, the local database, and in Azure.
1. In Visual Studio in the Solution Explorer, right-click the mobile service project and click **Set as startup project**.
2. From the **Tools** menu, expand **NuGet Package Manager**, then click **Package Manager Console**.
This displays the Package Manager Console, which you will use to manage your Code First Migrations.
3. In the Package Manager Console, run the following command:
PM> Enable-Migrations
This turns on Code First Migrations for your project.
4. In the console, run the following command:
PM> Add-Migration Initial
This creates a new migration named *Initial*. Migration code is stored in the Migrations project folder.
5. Expand the App_Start folder, open the WebApiConfig.cs project file and add the following **using** statements:
using System.Data.Entity.Migrations;
using todolistService.Migrations;
In the above code, you must replace the _todolistService_ string with the namespace of your project, which for the downloaded quickstart project is mobile_service_nameService.
6. In this same code file, comment-out the call to the **Database.SetInitializer** method and add the following code after it:
var migrator = new DbMigrator(new Configuration());
migrator.Update();
This disables the default Code First database initializer that drops and recreates the database and replaces it with an explicit request to apply the latest migration. At this point, any data model changes will result in an InvalidOperationException when the data is accessed, unless a migration has been created for it. Going forward, your service must use Code First Migrations to migrate data model changes to the database.
7. Press F5 to start the mobile service project on the local computer.
At this point, the database is in sync with the data model. If you provided seed data, you can verify it by clicking **Try it out**, **GET tables/todoitem**, then **Try this out** and **Send**. For more information, see [Seeding data in migrations].
8. Now make a change to your data model, such as adding a new UserId property to the TodoItem type, rebuild the project, and then in the Package Manager, run the following command:
PM> Add-Migration NewUserId
This creates a new migration named *NewUserId*. A new code file, which implements this change, is added in the Migrations folder
9. Press F5 again to restart the mobile service project on the local computer.
The migration is applied to the database and the database is again in sync with the data model. If you provided seed data, you can verify it by clicking **Try it out**, **GET tables/todoitem**, then **Try this out** and **Send**. For more information, see [Seeding data in migrations].
10. Republish the mobile service to Azure, then run the client app to access the data and verify that data loads and no error occur.
13. (Optional) In the [Azure classic portal], select your mobile service, click **Configure** > **SQL Database**. This navigates to the SQL Database page for your mobile service's database.
14. (Optional) Click **Manage**, log in to your SQL Database server, then click **Design** and verify that the schema changes have been made in Azure.
## Using Code First Migrations without an initializer
Before you use Code First Migrations with your .NET backend project, you should run a data model initializer. When you do NOT use an initializer, errors can occur when trying to apply migrations. If you choose not to use one of the pre-defined data model initializers, make sure that migrations is configured to use the EntityTableSqlGenerator as the SqlGenerator in the Migrations\Configuration.cs file, as in the following example:
public Configuration()
{
AutomaticMigrationsEnabled = false;
SetSqlGenerator("System.Data.SqlClient", new EntityTableSqlGenerator());
}
## Seeding data in migrations
You can have Migrations add seed data to the database when a migration is executed. The **Configuration** class has a **Seed** method that you can override to insert or update data. The Configuration.cs code file is added to the Migrations folder when Migrations are enabled. These examples show how to override the [Seed] method to seed data to the **TodoItems** table. The [Seed] method is called after migrating to the latest version.
### Seed a new table
The following code seeds the **TodoItems** table with new rows of data:
List todoItems = new List
{
new TodoItem { Id = "1", Text = "First item", Complete = false },
new TodoItem { Id = "2", Text = "Second item", Complete = false },
};
foreach (TodoItem todoItem in todoItems)
{
context.Set().Add(todoItem);
}
base.Seed(context);
### Seed a new column in a table
The following code seeds just the UserId column:
context.TodoItems.AddOrUpdate(
t => t.UserId,
new TodoItem { UserId = 1 },
new TodoItem { UserId = 1 },
new TodoItem { UserId = 2 }
);
base.Seed(context);
This code calls the [AddOrUpdate] helper extension method to add seed data to the new UserId column. By using [AddOrUpdate], duplicate rows are not created.
[Migrations]: #migrations
[Seeding data in migrations]: #seeding
[0]: ./media/mobile-services-dotnet-backend-how-to-use-code-first-migrations/navagate-to-sql-database.png
[1]: ./media/mobile-services-dotnet-backend-how-to-use-code-first-migrations/manage-sql-database.png
[2]: ./media/mobile-services-dotnet-backend-how-to-use-code-first-migrations/sql-database-drop-tables.png
[DropCreateDatabaseIfModelChanges]: http://msdn.microsoft.com/library/gg679604(v=vs.113).aspx
[Seed]: http://msdn.microsoft.com/library/hh829453(v=vs.113).aspx
[Azure classic portal]: https://manage.windowsazure.com/
[DbContext]: http://msdn.microsoft.com/library/system.data.entity.dbcontext(v=vs.113).aspx
[AddOrUpdate]: http://msdn.microsoft.com/library/system.data.entity.migrations.idbsetextensions.addorupdate(v=vs.103).aspx
[TableController]: https://msdn.microsoft.com/library/azure/dn643359.aspx
[EntityData]: https://msdn.microsoft.com/library/azure/microsoft.windowsazure.mobile.service.entitydata.aspx
[DbSet]: https://msdn.microsoft.com/library/azure/gg696460.aspx
================================================
FILE: docs/mobile-services-dotnet-backend-hybrid-connections-get-started.md
================================================
# Connect to an on-premises SQL Server from Azure Mobile Services using Hybrid Connections
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
When your enterprise transitions to the cloud, you might not be able to migrate all of your assets to Azure right away. Hybrid Connections lets Azure Mobile Services securely connect to your on-premises assets. In this way, you can make your on-premises data accessible to your mobile clients by using Azure. Supported assets include any resource that runs on a static TCP port, including Microsoft SQL Server, MySQL, HTTP Web APIs, and most custom web services. Hybrid Connections use Shared Access Signature (SAS) authorization to secure the connections from your mobile service and the on-premises Hybrid Connection Manager to the hybrid connection. For more information, see [Hybrid Connections Overview](https://azure.microsoft.com/en-us/documentation/articles/integration-hybrid-connection-overview/).
In this tutorial, you will learn how to modify a .NET backend mobile service to use a local on-premises SQL Server database instead of the default Azure SQL Database provisioned with your service. Hybrid Connections are also supported for a JavaScript backend mobile service, as described in [this article](http://blogs.msdn.com/b/azuremobile/archive/2014/05/12/connecting-to-an-external-database-with-node-js-backend-in-azure-mobile-services.aspx).
## Prerequisites ##
This tutorial requires you to have the following:
- **An existing .NET backend mobile service** Follow the tutorial [Get started with Mobile Services] to create and download a new .NET backend mobile service from the [Azure classic portal].
- **Visual Studio 2013** This a requirement for using To download a free trial version of Visual Studio 2013, see [Visual Studio Downloads](http://www.visualstudio.com/downloads/download-visual-studio-vs).
- **SQL Server 2014 Express with Tools** Download Microsoft SQL Server Express for free at the [Microsoft SQL Server Express Edition page](http://www.microsoft.com/en-us/server-cloud/Products/sql-server-editions/sql-server-express.aspx). Choose the **Download SQL Server Express** and fill out your profile, choosing **SQL Server 2014 Express with Tools**, then click continue. This starts the download of the installer for both SQL Server Express and the SQL Server Express Management Tools. Save the installer package to your on-premises computer.
- **An on-premises computer** You can run the Hybrid Connections Manger on the same on-premises computer as your SQL Server instance, or you can run each on a separate computer. The computer on which the Hybrid Connection Manager runs must meet the following criteria:
- Be able to connect to Azure over port 5671.
- Be able to access the *hostname*:*portnumber* of the computer running your SQL Server instance.
For more information see [Hybrid Connections Overview](https://azure.microsoft.com/en-us/documentation/articles/integration-hybrid-connection-overview/).
## Install SQL Server Express, enable TCP/IP, and create a SQL Server database on-premises
This section shows you how to install a SQL Server Express, enable TCP/IP, set a static port, and create a database that can be used with Hybrid Connections.
### Install SQL Server Express
To use an on-premises SQL Server or SQL Server Express database with a hybrid connection, TCP/IP needs to be enabled on a static port. Default instances on SQL Server use static port 1433, whereas named instances do not. Because of this, we will install the default instance. If you already have the default instance of SQL Server Express installed, you can skip this section.
1. To install SQL Server Express, run the **SQLEXPRWT_x64_ENU.exe** or **SQLEXPR_x86_ENU.exe** file that you downloaded. The SQL Server Installation Center wizard appears.
2. Choose **New SQL Server stand-alone installation or add features to an existing installation**, follow the instructions, accepting the default choices and settings, until you get to the **Instance Configuration** page.
3. On the **Instance Configuration** page, choose **Default instance**, then accept the default settings on the **Server Configuration** page.
>[AZURE.NOTE]If you already have a default instance of SQL Server installed, you can skip to the next section and use this instance with Hybrid Connections.
5. On the **Database Engine Configuration** page, under **Authentication Mode**, choose **Mixed Mode (SQL Server authentication and Windows authentication)**, and provide a secure password for the built-in **sa** administrator account.
In this tutorial, you will be using SQL Server authentication. Be sure to remember the password that you provide, because you will need it later.
6. Finish the wizard to complete the installation.
### Enable TCP/IP and setting a static port
This section uses SQL Server Configuration Manager, which was installed when you installed SQL Server Express, to enable TCP/IP and set a static IP address.
1. Follow the steps in [Enable TCP/IP Network Protocol for SQL Server](http://technet.microsoft.com/library/hh231672%28v=sql.110%29.aspx) to enable TCP/IP access to the instance.
2. (Optional) If you are not able to use the default instance, you must follow the steps in [Configure a Server to Listen on a Specific TCP Port ](https://msdn.microsoft.com/library/ms177440.aspx) to set a static port for the instance. If you complete this step, you will connect using the new port that you define, instead of port 1433.
3. (Optional) If needed, add exceptions in the firewall to allow remote access to the SQL Server process (sqlservr.exe).
### Create a new database in the on-premises SQL Server instance
1. In SQL Server Management Studio, connect to the SQL Server you just installed. (If the **Connect to Server** dialog does not appear automatically, navigate to **Object Explorer** in the left pane, click **Connect**, and then click **Database Engine**.)

For **Server type**, choose **Database Engine**. For **Server name**, you can use **localhost** or the name of the computer where you installed SQL Server. Choose **SQL Server authentication**, and supply the password for the sa login that you created earlier.
2. To create a new database by using SQL Server Management Studio, right-click **Databases** in Object Explorer, and then click **New Database**.
3. In the **New Database** dialog, type `OnPremisesDB`, and then click **OK**.
4. In Object Explorer, if you expand **Databases**, you will see that the new database is created.
### Create a new SQL Server login and set permissions
Finally, you will create a new SQL Server login with restricted permissions. Your Azure service will connect to the on-premise SQL Server using this login instead of the built-in sa login, which has full permissions on the server.
1. In SQL Server Management Studio Object Explorer, right-click the **OnPremisesDB** database and click **New Query**.
2. Paste the following TSQL query into the query window.
USE [master]
GO
/* Replace the PASSWORD in the following statement with a secure password.
If you save this script, make sure that you secure the file to
securely maintain the password. */
CREATE LOGIN [HybridConnectionLogin] WITH PASSWORD=N'<**secure_password**>',
DEFAULT_DATABASE=[OnPremisesDB], DEFAULT_LANGUAGE=[us_english],
CHECK_EXPIRATION=OFF, CHECK_POLICY=ON
GO
USE [OnPremisesDB]
GO
CREATE USER [HybridConnectionLogin] FOR LOGIN [HybridConnectionLogin]
WITH DEFAULT_SCHEMA=[dbo]
GO
GRANT CONNECT TO [HybridConnectionLogin]
GRANT CREATE TABLE TO [HybridConnectionLogin]
GRANT CREATE SCHEMA TO [HybridConnectionLogin]
GO
3. In the above script, replace the string `<**secure_password**>` with a secure password for the new *HybridConnectionsLogin*.
4. **Execute** the query to create the new login and grant the required permissions in the on-premises database.
## Create a Hybrid Connection
1. On the on-premises machine, log on to the [Azure Management Portal](http://manager.windowsazure.com) (this is the old portal).
2. At the bottom of the navigation pane, select **+NEW** > **App Services** > **BizTalk Service** > **Custom Create**.
3. Provide a **BizTalk Service Name** and select an **Edition**.
This tutorial uses **mobile1**. You will need to supply a unique name for your new BizTalk Service.
4. Once the BizTalk Service has been created, select the **Hybrid Connections** tab, then click **Add**.

This creates a new hybrid connection.
5. Provide a **Name** and **Host Name** for your hybrid connection and set **Port** to `1433`.

The host name is the name of the on-premises server. This configures the hybrid connection to access SQL Server running on port 1433. If you are using a named SQL Server instance, instead use the static port you defined earlier.
6. After the new connection is created, the status of the of the new connection shows **On-premises setup incomplete**.
7. Navigate back to your mobile service, click **Configure**, scroll down to **Hybrid connections** and click **Add hybrid connection**, then select the hybrid connection that you just created and click **OK**.
This enables your mobile service to use your new hybrid connection.
Next, you'll need to install the Hybrid Connection Manager on the on-premises computer.
## Install the on-premises Hybrid Connection Manager to complete the connection
The Hybrid Connection Manager enables your on-premises machine to connect to Azure and relay TCP traffic. You must install the manager to an on-premises computer that can connect to the your SQL Server instance.
1. The connection you just created should have a **Status** of **On-premesis setup incomplete**. Click this connection and click **On-premises Setup**.

2. Click **Install and Configure**.
This installs a customized instance of the Connection Manager, which is already pre-configured to work with the hybrid connection you just created.
3. Complete the rest of the setup steps for the Connection Manager.
After the installation is complete, the hybrid connection status will change to **1 Instance Connected**. You may need to refresh the browser and wait a few minutes.
The hybrid connection setup is now complete.
## Configure the mobile service project to connect to the SQL Server database
In this step, you define a connection string for the on-premises database and modify the mobile service to use this connection.
1. In Visual Studio 2013, open the project that defines your .NET backend mobile service.
To learn how to download your .NET backend project, see [Get started with Mobile Services](mobile-services-dotnet-backend-windows-store-dotnet-get-started.md) .
2. In Solution Explorer, open the Web.config file, locate the **connectionStrings** section, add a new SqlClient entry like the following, which points to the on-premises SQL Server database:
Remember to replace `<**secure_password**>` in this string with the password you created for the *HbyridConnectionLogin*.
3. Click **Save** in Visual Studio to save the Web.config file.
> [AZURE.NOTE]This connection setting is used when running on the local computer. When running in Azure, this setting is overriden by the connection setting defined in the portal.
4. Expand the **Models** folder and open the data model file, which ends in *Context.cs*.
6. Modify the **DbContext** instance constructor to pass the value `OnPremisesDBConnection` to the base **DbContext** constructor, similar to the following snippet:
public class hybridService1Context : DbContext
{
public hybridService1Context()
: base("OnPremisesDBConnection")
{
}
}
The service will now use the new connection to the SQL Server database.
## Test the database connection locally
Before publishing to Azure and using the hybrid connection, it's a good idea to make sure that the database connection works when running locally. That way you can more easily diagnose and correct any connection issues before you republish and start using the hybrid connection.
1. In Visual Studio in Solution Explorer, right click the service project and click **Start new instance** under the **Debug** context menu.

Visual Studio opens the default web page for your service. By default, Visual Studio hosts your mobile service locally in IIS Express.
2. Right-click the tray icon for IIS Express on the Windows taskbar and verify that your mobile service has started.

3. On the start page of your .NET backend, click **try it out**.

This displays the API documentation page, which you can use to test the mobile service.
>[AZURE.NOTE]Authentication is not required to access this page when running locally. When running in Azure, you must supply the application key as the password (with no username) to access this page.
4. Click the **GET tables/TodoItem** link.

This displays the GET response page for the API.
5. Click **try this out** and then click **send**.

This sends a GET request to the local mobile service to return all rows in the TodoItem table. Because the table is seeded by the initializer, two TodoItem objects are returned in the body of the response message. For more information about initializers, see [How to make data model changes to a .NET backend mobile service](mobile-services-dotnet-backend-how-to-use-code-first-migrations.md).

## Update Azure to use the on-premises connection string
Now that you have verified the database connection, you need to add an app setting for this new connection string so that it can be used from Azure and publish the mobile service to Azure.
1. In the [Azure classic portal], browse to your mobile service.
1. Click the **Configure** tab, and locate **Connection Strings** section.

2. Add an new connection **SQL Server** string named `OnPremisesDBConnection` with a value like the following:
Server=OnPremisesServer,1433;Database=OnPremisesDB;User ID=HybridConnectionsLogin;Password=<**secure_password**>
Replace `<**secure_password**>` with the secure password for *HybridConnectionLogin*.
2. Press **Save** to save the hybrid connection and connection string you just created.
3. Using Visual Studio, publish your updated mobile service project to Azure.
The service start page is displayed.
4. Using either the **Try it now** button on the start page as before or using a client app connected to your mobile service, invoke some operations that generate database changes.
>[AZURE.NOTE]When you use the **Try it now** button to launch the Help API pages, remember to supply your application key as the password (with a blank username).
4. In SQL Server Management Studio, connect to your SQL Server instance, open the Object Explorer, expand the **OnPremisesDB** database and expand **Tables**.
5. Right-click the **hybridService1.TodoItems** table and choose **Select Top 1000 Rows** to view the results.
Note that changes generated in your app have been saved by your mobile service to your on-premises database using the hybrid connection.
## See Also ##
+ [Hybrid Connections web site](https://azure.microsoft.com/services/biztalk-services/)
+ [Hybrid Connections overview](https://azure.microsoft.com/en-us/documentation/articles/integration-hybrid-connection-overview/)
+ [BizTalk Services: Dashboard, Monitor, Scale, Configure, and Hybrid Connection tabs](https://azure.microsoft.com/en-us/documentation/articles/biztalk-dashboard-monitor-scale-tabs/)
+ [How to make data model changes to a .NET backend mobile service](mobile-services-dotnet-backend-how-to-use-code-first-migrations.md)
[Azure classic portal]: http://manage.windowsazure.com
[Get started with Mobile Services]: mobile-services-dotnet-backend-windows-store-dotnet-get-started.md
================================================
FILE: docs/mobile-services-dotnet-backend-ios-adal-sso-authentication.md
================================================
# Authenticate your app with Active Directory Authentication Library Single Sign-On
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
> [AZURE.SELECTOR-LIST (Platform | Backend)]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-adal-sso-authentication.md)
- [(Windows 8.x Store C# | .NET)](mobile-services-windows-store-dotnet-adal-sso-authentication.md)
## Overview
In this tutorial, you add authentication to the quickstart project using the Active Directory Authentication Library.
To be able to authenticate users, you must register your application with the Azure Active Directory (AAD). This is done in two steps. First, you must register your mobile service and expose permissions on it. Second, you must register your iOS app and grant it access to those permissions
>[AZURE.NOTE] This tutorial is intended to help you better understand how Mobile Services enables you to do single sign-on Azure Active Directory authentication for iOS apps. If this is your first experience with Mobile Services, complete the tutorial [Get started with Mobile Services].
## Prerequisites
This tutorial requires the following:
* XCode 4.5 and iOS 6.0 (or later versions)
* Completion of the [Get started with Mobile Services] tutorial.
* Completion of the [Register your apps to use an Azure Active Directory Account login]
* Microsoft Azure Mobile Services SDK
* The [Active Directory Authentication Library for iOS]
## Register your client app with the Azure Active Directory
1. Navigate to **Active Directory** in the [Azure classic portal](https://manage.windowsazure.com/), then click your directory.

2. Click the **Applications** tab at the top, then click to **ADD** an app.

3. Click **Add an application my organization is developing**.
4. In the Add Application Wizard, enter a **Name** for your application and click the **Native Client Application** type. Then click to continue.

5. In the **Redirect URI** box, enter the /login/done endpoint for your mobile service. This value should be similar to https://todolist.azure-mobile.net/login/done.

6. Click the **Configure** tab for the native application and copy the **Client ID**. You will need this later.

7. Scroll the page down to the **permissions to other applications** section and click the **Add application** button. Choose **Other** from the Show menu and search for todo. Click **TodoList** to add it the mobile service you registered earlier and click the checkmark for done. Grant access to the mobile service application. Then click **Save**

Your mobile service is now configured in AAD to receive single sign-on logins from your app.
## Configure the mobile service to require authentication
By default, all requests to mobile service resources are restricted to clients that present the application key, which does not strictly secure access to resources. To secure your resources, you must restrict access to only authenticated clients.
1. In Visual Studio, open your mobile service project, expand the Controllers folder, and open **TodoItemController.cs**. The **TodoItemController** class implements data access for the TodoItem table. Add the following `using` statement:
using Microsoft.WindowsAzure.Mobile.Service.Security;
2. Apply the following _AuthorizeLevel_ attribute to the **TodoItemController** class.
[AuthorizeLevel(AuthorizationLevel.User)]
This makes sure that all operations against the _TodoItem_ table require an authenticated user. You can also apply the *AuthorizeLevel* attribute at the method level.
3. (Optional) If you wish to debug authentication locally, expand the `App_Start` folder, open **WebApiConfig.cs**, and add the following code to the **Register** method.
config.SetIsHosted(true);
This tells the local mobile service project to run as if it is being hosted in Azure, including honoring the *AuthorizeLevel* settings. Without this setting, all HTTP requests to localhost are permitted without authentication despite the *AuthorizeLevel* setting. When you enable self-hosted mode, you also need to set a value for the local application key.
4. (Optional) In the web.config project file, set a string value for the `MS_ApplicationKey` app setting.
This is the password that you use (with no username) to test the API help pages when you run the service locally. This string value is not used by the live site in Azure, and you do not need to use the actual application key; any valid string value will work.
4. Republish your project.
## Add authentication code to the client app
1. Download the [Active Directory Authentication Library for iOS] and include it in your project. Be sure to also add the storyboards from the ADAL source.
2. In the QSTodoListViewController, include ADAL with the following:
#import "ADALiOS/ADAuthenticationContext.h"
2. Then add the following method:
- (void) loginAndGetData
{
MSClient *client = self.todoService.client;
if (client.currentUser != nil) {
return;
}
NSString *authority = @"";
NSString *resourceURI = @"";
NSString *clientID = @"";
NSString *redirectURI = @"";
ADAuthenticationError *error;
ADAuthenticationContext *authContext = [ADAuthenticationContext authenticationContextWithAuthority:authority error:&error];
NSURL *redirectUri = [[NSURL alloc]initWithString:redirectURI];
[authContext acquireTokenWithResource:resourceURI clientId:clientID redirectUri:redirectUri completionBlock:^(ADAuthenticationResult *result) {
if (result.tokenCacheStoreItem == nil)
{
return;
}
else
{
NSDictionary *payload = @{
@"access_token" : result.tokenCacheStoreItem.accessToken
};
[client loginWithProvider:@"windowsazureactivedirectory" token:payload completion:^(MSUser *user, NSError *error) {
[self refresh];
}];
}
}];
}
6. In the code for the `loginAndGetData` method above, replace **INSERT-AUTHORITY-HERE** with the name of the tenant in which you provisioned your application, the format should be https://login.windows.net/tenant-name.onmicrosoft.com. This value can be copied out of the Domain tab in your Azure Active Directory in the [Azure classic portal].
7. In the code for the `loginAndGetData` method above, replace **INSERT-RESOURCE-URI-HERE** with the **App ID URI** for your mobile service. If you followed the [How to Register with the Azure Active Directory] topic your App ID URI should be similar to https://todolist.azure-mobile.net/login/aad.
8. In the code for the `loginAndGetData` method above, replace **INSERT-CLIENT-ID-HERE** with the client ID you copied from the native client application.
9. In the code for the `loginAndGetData` method above, replace **INSERT-REDIRECT-URI-HERE** with the /login/done endpoint for your mobile service. This should be similar to https://todolist.azure-mobile.net/login/done.
3. In the QSTodoListViewController, modify `ViewDidLoad` by replacing `[self refresh]` with the following:
[self loginAndGetData];
## Test the client using authentication
1. From the Product menu, click Run to start the app
2. You will receive a prompt to login against your Azure Active Directory.
3. The app authenticates and returns the todo items.

[Get started with Mobile Services]: mobile-services-dotnet-backend-ios-get-started.md
[Register your apps to use an Azure Active Directory Account login]:mobile-services-how-to-register-active-directory-authentication.md
[How to Register with the Azure Active Directory]: mobile-services-how-to-register-active-directory-authentication.md
[Azure classic portal]: https://manage.windowsazure.com/
[Active Directory Authentication Library for iOS]: https://github.com/MSOpenTech/azure-activedirectory-library-for-ios
================================================
FILE: docs/mobile-services-dotnet-backend-ios-get-started-push.md
================================================
# Add Push Notifications to iOS App and .NET Backend
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-push.md)
- [(iOS | JavaScript)](mobile-services-javascript-backend-ios-get-started-push.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-push.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-get-started-push.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-javascript-backend-windows-phone-get-started-push.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started-push.md)
- [(Android | Javascript)](mobile-services-javascript-backend-android-get-started-push.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-push.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-push.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-push.md)
- [(Xamarin.Forms | JavaScript)](partner-xamarin-mobile-services-xamarin-forms-get-started-push.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This topic shows you how to add push notifications to the [quickstart project](mobile-services-dotnet-backend-ios-get-started.md), so that your mobile service sends a push notification each time a record is inserted. You must complete [Get Started with Mobile Services] first.
* [Register an App ID for your app](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/MaintainingProfiles/MaintainingProfiles.html#//apple_ref/doc/uid/TP40012582-CH30-SW991). Create an explicit App ID (not a wildcard App ID) and for **Bundle ID**, use the exact **Bundle ID** that is in your Xcode quickstart project. It is also crucial that you check the **Push Notifications** option.
* Next, [configuring push notifications](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/AddingCapabilities/AddingCapabilities.html#//apple_ref/doc/uid/TP40012582-CH26-SW6). You may create either a "Development" or "Distribution" SSL certificate (remember to select the corresponding option in the Azure portal later.)
## Configure Azure to Send Push Notifications
* Follow the steps at [Installing a Client SSL Signing Identity on the Server](https://developer.apple.com/library/prerelease/ios/documentation/IDEs/Conceptual/AppDistributionGuide/AddingCapabilities/AddingCapabilities.html#//apple_ref/doc/uid/TP40012582-CH26-SW16) to export the certificate you downloaded in the previous step to a .p12 file.
* In the Azure classic portal, click **Mobile Services** > your app > the **Push** tab > **apple push notification settings** > "**Upload**. Upload the .p12 file, making sure that the correct **Mode** is selected (either Sandbox or Production, corresponding to whether the client SSL certificate you generated was Development or Distribution.) Your mobile service is now configured to work with push notifications on iOS!
## Update Backend Code to Send Push Notifications
* Open Visual Studio project > **Controllers** folder > **TodoItemController.cs** > method `PostTodoItem`. Replace the method with the following. When a todo item is inserted, this code sends out a push notification with the item text. If there's an error, the code adds an error log entry that is viewable via the logs section of the portal.
```
public async Task PostTodoItem(TodoItem item)
{
TodoItem current = await InsertAsync(item);
ApplePushMessage message = new ApplePushMessage(item.Text, System.TimeSpan.FromHours(1));
try
{
var result = await Services.Push.SendAsync(message);
Services.Log.Info(result.State.ToString());
}
catch (System.Exception ex)
{
Services.Log.Error(ex.Message, null, "Push.SendAsync Error");
}
return CreatedAtRoute("Tables", new { id = current.Id }, current);
}
```
## Publish Mobile Service to Azure
1. In Visual Studio, right-click the project, click **Publish** > **Microsoft Azure Mobile Services**. Instead of using Visual Studio, [you may also use Git](./
mobile-services-dotnet-backend-store-code-source-control.md).
2. Sign in with Azure credentials and select your service from **Existing Mobile Services**. Visual Studio downloads your publish settings directly from Azure. Finally, click **Publish**.
## Add Push Notifications to App
* In QSAppDelegate.m, import the iOS SDK and QSTodoService.h:
```
#import
#import "QSTodoService.h"
```
* In `didFinishLaunchingWithOptions` in QSAppDelegate.m, insert the following lines right before `return YES;`:
```
UIUserNotificationSettings* notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
```
* In QSAppDelegate.m, add the following handler methods. Your app is now updated to support push notifications.
```
// Registration with APNs is successful
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
QSTodoService *todoService = [QSTodoService defaultService];
MSClient *client = todoService.client;
[client.push registerNativeWithDeviceToken:deviceToken tags:nil completion:^(NSError *error) {
if (error != nil) {
NSLog(@"Error registering for notifications: %@", error);
}
}];
}
// Handle any failure to register
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:
(NSError *)error {
NSLog(@"Failed to register for remote notifications: %@", error);
}
// Use userInfo in the payload to display a UIAlertView.
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo {
NSLog(@"%@", userInfo);
NSDictionary *apsPayload = userInfo[@"aps"];
NSString *alertString = apsPayload[@"alert"];
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:@"Notification"
message:alertString
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
}
```
* In Xcode, press **Run** and start the app on an iOS device (not the simulator.) Click **OK** to accept push notifications; this request occurs the first time the app runs.
* In the app, add a new item and click **+**.
* Verify that a notification is received, then click **OK** to dismiss the notification. You have now successfully completed this tutorial.

[Generate the certificate signing request]: #certificates
[Register your app and enable push notifications]: #register
[Create a provisioning profile for the app]: #profile
[Configure Mobile Services]: #configure
[Update scripts to send push notifications]: #update-scripts
[Add push notifications to the app]: #add-push
[Insert data to receive notifications]: #test
[Test the app against the published mobile service]: #test-app
[Next Steps]:#next-steps
[Download the service locally]: #download-the-service-locally
[Test the mobile service]: #test-the-service
[Publish the mobile service to Azure]: #publish-mobile-service
[5]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-step5.png
[6]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-step6.png
[7]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-step7.png
[9]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-step9.png
[10]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-step10.png
[17]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-step17.png
[18]: ./media/mobile-services-ios-get-started-push/mobile-services-selection.png
[19]: ./media/mobile-services-ios-get-started-push/mobile-push-tab-ios.png
[20]: ./media/mobile-services-ios-get-started-push/mobile-push-tab-ios-upload.png
[21]: ./media/mobile-services-ios-get-started-push/mobile-portal-data-tables.png
[22]: ./media/mobile-services-ios-get-started-push/mobile-insert-script-push2.png
[23]: ./media/mobile-services-ios-get-started-push/mobile-quickstart-push1-ios.png
[24]: ./media/mobile-services-ios-get-started-push/mobile-quickstart-push2-ios.png
[25]: ./media/mobile-services-ios-get-started-push/mobile-quickstart-push3-ios.png
[26]: ./media/mobile-services-ios-get-started-push/mobile-quickstart-push4-ios.png
[28]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-step18.png
[101]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-01.png
[102]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-02.png
[103]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-03.png
[104]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-04.png
[105]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-05.png
[106]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-06.png
[107]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-07.png
[108]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-08.png
[110]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-10.png
[111]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-11.png
[112]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-12.png
[113]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-13.png
[114]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-14.png
[115]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-15.png
[116]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-16.png
[117]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-17.png
[Install Xcode]: https://go.microsoft.com/fwLink/p/?LinkID=266532
[iOS Provisioning Portal]: http://go.microsoft.com/fwlink/p/?LinkId=272456
[Mobile Services iOS SDK]: https://go.microsoft.com/fwLink/p/?LinkID=266533
[Apple Push Notification Service]: http://go.microsoft.com/fwlink/p/?LinkId=272584
[Get started with Mobile Services]: mobile-services-dotnet-backend-ios-get-started.md
[apns object]: http://go.microsoft.com/fwlink/p/?LinkId=272333
[Get started with authentication]: mobile-services-dotnet-backend-ios-get-started-users.md
[Mobile Services Objective-C how-to conceptual reference]: mobile-services-windows-dotnet-how-to-use-client-library.md
[What are Notification Hubs?]: https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-push-notification-overview/
[Send broadcast notifications to subscribers]: https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-ios-xplat-segmented-apns-push-notification/
[Send template-based notifications to subscribers]: https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-ios-xplat-localized-apns-push-notification/
================================================
FILE: docs/mobile-services-dotnet-backend-ios-get-started-users.md
================================================
# Add Authentication to Existing Azure Mobile Services app
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-users.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started-users.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-users.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-get-started-users.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-windows-phone-get-started-users.md)
- [(Android | Javascript)](mobile-services-android-get-started-users.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started-users.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-users.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-users.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-users.md)
- [(HTML | Javascript)](mobile-services-html-get-started-users.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
In this tutorial, you add authentication to the Quick Start project using a supported identity provider. This tutorial is based on the [Mobile Services Quick Start tutorial], which you must complete first.
## Register app for authentication and configure Mobile Services
1. In the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Dashboard**, and make a note of the **Mobile Service URL** value.
2. Register your app with one or more of the following authentication providers:
* [Google](./
mobile-services-how-to-register-google-authentication.md)
* [Facebook](./
mobile-services-how-to-register-facebook-authentication.md)
* [Twitter](./
mobile-services-how-to-register-twitter-authentication.md)
* [Microsoft](./
mobile-services-how-to-register-microsoft-authentication.md)
* [Azure Active Directory](./
mobile-services-how-to-register-active-directory-authentication.md).
Make a note of the client identity and client secret values generated by the provider. Do not distribute or share the client secret.
3. Back in the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Identity** > your identity provider settings, then enter the client ID and secret value from your provider.
You've now configured both your app and your mobile service to work with your auth provider. You may optionally repeat all these steps for each additional identity provider you'd like to support.
> [AZURE.IMPORTANT] Verify that you've set the correct redirect URI on your identity provider's developer site. As described in the linked instructions for each provider above, the redirect URI may be different for a .NET backend service vs. for a JavaScript backend service. An incorrectly configured redirect URI may result in the login screen not being displayed properly and the app malfunctioning in unexpected ways.
### (Optional) Configure your .NET Mobile Service for Azure Active Directory
>[AZURE.NOTE] These steps are optional because they only apply to the Azure Active Directory login provider.
1. Install the [WindowsAzure.MobileServices.Backend.Security NuGet package](https://www.nuget.org/packages/WindowsAzure.MobileServices.Backend.Security).
2. In Visual Studio expand App_Start and open WebApiConfig.cs. Add the following `using` statement at the top:
using Microsoft.WindowsAzure.Mobile.Service.Security.Providers;
3. Also in WebApiConfig.cs, add the following code to the `Register` method, immediately after `options` is instantiated:
options.LoginProviders.Remove(typeof(AzureActiveDirectoryLoginProvider));
options.LoginProviders.Add(typeof(AzureActiveDirectoryExtendedLoginProvider));
## Restrict permissions to authenticated users
By default, all requests to mobile service resources are restricted to clients that present the application key, which does not strictly secure access to resources. To secure your resources, you must restrict access to only authenticated clients.
1. In Visual Studio, open your mobile service project, expand the Controllers folder, and open **TodoItemController.cs**. The **TodoItemController** class implements data access for the TodoItem table. Add the following `using` statement:
using Microsoft.WindowsAzure.Mobile.Service.Security;
2. Apply the following _AuthorizeLevel_ attribute to the **TodoItemController** class.
[AuthorizeLevel(AuthorizationLevel.User)]
This makes sure that all operations against the _TodoItem_ table require an authenticated user. You can also apply the *AuthorizeLevel* attribute at the method level.
3. (Optional) If you wish to debug authentication locally, expand the `App_Start` folder, open **WebApiConfig.cs**, and add the following code to the **Register** method.
config.SetIsHosted(true);
This tells the local mobile service project to run as if it is being hosted in Azure, including honoring the *AuthorizeLevel* settings. Without this setting, all HTTP requests to localhost are permitted without authentication despite the *AuthorizeLevel* setting. When you enable self-hosted mode, you also need to set a value for the local application key.
4. (Optional) In the web.config project file, set a string value for the `MS_ApplicationKey` app setting.
This is the password that you use (with no username) to test the API help pages when you run the service locally. This string value is not used by the live site in Azure, and you do not need to use the actual application key; any valid string value will work.
4. Republish your project.
In Xcode, open the project. Press the **Run** button to start the app. Verify that an exception with a status code of 401 (Unauthorized) is raised after the app starts. This happens because the app attempts to access Mobile Services as an unauthenticated user, but the _TodoItem_ table now requires authentication.
## Add authentication to app
* Open **QSTodoListViewController.m** and add the following method. Change _facebook_ to _microsoftaccount_, _twitter_, _google_, or _windowsazureactivedirectory_ if you're not using Facebook as your identity provider.
```
- (void) loginAndGetData
{
MSClient *client = self.todoService.client;
if (client.currentUser != nil) {
return;
}
[client loginWithProvider:@"facebook" controller:self animated:YES completion:^(MSUser *user, NSError *error) {
[self refresh];
}];
}
```
* Replace `[self refresh]` in `viewDidLoad` with the following:
```
[self loginAndGetData];
```
* Press **Run** to start the app, and then log in. When you are logged in, you should be able to view the Todo list and make updates.
## Store authentication tokens in app
The previous example contacts both the identity provider and the mobile service every time the app starts. Instead, you can cache the authorization token and try to use it first.
* The recommended way to encrypt and store authentication tokens on an iOS client is use the iOS Keychain. We'll use [SSKeychain](https://github.com/soffes/sskeychain) -- a simple wrapper around the iOS Keychain. Follow the instructions on the SSKeychain page and add it to your project. Verify that the **Enable Modules** setting is enabled in the project's **Build Settings** (section **Apple LLVM - Languages - Modules**.)
* Open **QSTodoListViewController.m** and add the following code:
```
- (void) saveAuthInfo {
[SSKeychain setPassword:self.todoService.client.currentUser.mobileServiceAuthenticationToken forService:@"AzureMobileServiceTutorial" account:self.todoService.client.currentUser.userId]
}
- (void)loadAuthInfo {
NSString *userid = [[SSKeychain accountsForService:@"AzureMobileServiceTutorial"][0] valueForKey:@"acct"];
if (userid) {
NSLog(@"userid: %@", userid);
self.todoService.client.currentUser = [[MSUser alloc] initWithUserId:userid];
self.todoService.client.currentUser.mobileServiceAuthenticationToken = [SSKeychain passwordForService:@"AzureMobileServiceTutorial" account:userid];
}
}
```
* In `loginAndGetData`, modify `loginWithProvider:controller:animated:completion:`'s completion block. Add the following line right before `[self refresh]` to store the user ID and token properties:
```
[self saveAuthInfo];
```
* Let's load the user ID and token when the app starts. In the `viewDidLoad` in **QSTodoListViewController.m**, add this right after`self.todoService` is initialized.
```
[self loadAuthInfo];
```
## Next steps
In the next tutorial, [Service-side authorization of Mobile Services users], you will user the user ID value to filter returned data.
[Register your app for authentication and configure Mobile Services]: #register
[Restrict table permissions to authenticated users]: #permissions
[Add authentication to the app]: #add-authentication
[Next Steps]:#next-steps
[Storing authentication tokens in your app]:#store-authentication
[Service-side authorization of Mobile Services users]: mobile-services-dotnet-backend-service-side-authorization.md
[Mobile Services Quick Start tutorial]: mobile-services-dotnet-backend-ios-get-started.md
[Get started with authentication]: mobile-services-dotnet-backend-ios-get-started-users.md
[Get started with push notifications]: mobile-services-dotnet-backend-ios-get-started-push.md
[Authorize users with scripts]: mobile-services-dotnet-backend-service-side-authorization.md
[Mobile Services .NET How-to Conceptual Reference]: https://azure.microsoft.com/develop/mobile/how-to-guides/work-with-net-client-library
[Register your Windows Store app package for Microsoft authentication]: mobile-services-how-to-register-store-app-package-microsoft-authentication.md
================================================
FILE: docs/mobile-services-dotnet-backend-ios-get-started.md
================================================
# Get started with Mobile Services
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal JavaScript | Javascript)](mobile-services-javascript-backend-windows-store-javascript-get-started.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started.md)
- [(Android | Javascript)](mobile-services-android-get-started.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started.md)
- [(HTML | Javascript)](mobile-services-html-get-started.md)
- [(PhoneGap | Javascript)](mobile-services-javascript-backend-phonegap-get-started.md)
- [(Sencha | Javascript)](partner-sencha-mobile-services-get-started.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This tutorial shows you how to add a cloud-based backend service to an iOS app using Azure Mobile Services. In this tutorial, you will create both a new mobile service and a simple _To do list_ app that stores app data in the new mobile service. The mobile service uses .NET and Visual Studio for server-side business logic. To create a mobile service with server-side business logic in JavaScript, see the [JavaScript backend version] of this topic.
> [AZURE.NOTE] To complete this tutorial, you need an Azure account. If you don't have an account, you can sign up for an Azure trial and get [free mobile services that you can keep using even after your trial ends](https://azure.microsoft.com/pricing/details/mobile-services/). For details, see [Azure Free Trial](https://azure.microsoft.com/pricing/free-trial/?WT.mc_id=AE564AB28&returnurl=http%3A%2F%2Fazure.microsoft.com%2Fdocumentation%2Farticles%2Fmobile-services-dotnet-backend-ios-get-started%2F).
## Create a new mobile service
Follow these steps to create a new mobile service.
1. Log into the [Azure classic portal](https://manage.windowsazure.com/). At the bottom of the navigation pane, click **+NEW**. Expand **Compute** and **Mobile Service**, then click **Create**.

This displays the **Create a Mobile Service** dialog.
2. In the **Create a Mobile Service** page, select **Create a free 20 MB SQL Database**, select **.NET** runtime, then type a subdomain name for the new mobile service in the **URL** textbox. Click the right arrow button to go to the next page.

This displays the **Specify database settings** page.
> [AZURE.NOTE] As part of this tutorial, you create a new SQL Database instance and server. You can reuse this new database and administer it as you would any other SQL Database instance. If you already have a database in the same region as the new mobile service, you can instead choose **Use existing Database** and then select that database. The use of a database in a different region is not recommended because of additional bandwidth costs and higher latencies.
3. In **Name**, type the name of the new database, then type **Login name**, which is the administrator login name for the new SQL Database server, type and confirm the password, and click the check button to complete the process.

You have now created a new mobile service that can be used by your mobile apps.
## Download the mobile service and app to your local computer
Now that you have created the mobile service, download projects that you can run locally.
1. Click the mobile service that you just created, then in the Quick Start tab, click **iOS** under **Choose a platform** and expand **Create a new iOS app**.
2. On your Windows PC, click **Download** under **Download and publish your service to the cloud**. This downloads the Visual Studio project that implements your mobile service. Save the compressed project file to your local computer, and make a note of where you saved it.
3. On your Mac, click **Download** under **Download and run your app**. This downloads the project for the sample _To do list_ application that is connected to your mobile service, along with the Mobile Services iOS SDK. Save the compressed project file to your local computer, and make a note of where you saved it.
## Test the mobile service
The mobile service project lets you run your new mobile service locally. This makes it easy to debug your service code before you even publish it to Azure.
1. On your Windows PC, download your personalized server project, extract it, and then open it in Visual Studio.
2. Press the **F5** key to rebuild the project and start the mobile service locally. A web page is displayed after the mobile service starts successfully.
## Publish your mobile service
1. In Visual Studio, right-click the project, click **Publish** > **Microsoft Azure Mobile Services**. Instead of using Visual Studio, [you may also use Git](./
mobile-services-dotnet-backend-store-code-source-control.md).
2. Sign in with Azure credentials and select your service from **Existing Mobile Services**. Visual Studio downloads your publish settings directly from Azure. Finally, click **Publish**.
## Run your new iOS app
The final stage of this tutorial is to build and run your new app.
1. Browse to the location where you saved the compressed project files, expand the files on your computer, and open the project file using Xcode.
2. Press the **Run** button to build the project and start the app in the iPhone emulator.
3. In the app, type meaningful text, such as _Complete the tutorial_ and then click the plus (**+**) icon.

This sends a POST request to the new mobile service hosted in Azure. Data from the request is inserted into the TodoItem table. Items stored in the table are returned by the mobile service, and the data is displayed in the list.
## Next Steps
This shows how to run your new client app against the mobile service running in Azure. Before you can test the iOS app with the mobile service running on a local computer, you must configure the Web server and firewall to allow access from your iOS development computer. For more information, see [Configure the local web server to allow connections to a local mobile service](mobile-services-dotnet-backend-how-to-configure-iis-express.md).
Learn how to perform additional important tasks in Mobile Services:
* [Get started with offline data sync]
Learn how to use offline data sync to make your app responsive and robust.
* [Add authentication to an existing app]
Learn how to authenticate users of your app with an identity provider.
* [Add push notifications to an existing app]
Learn how to send a very basic push notification to your app.
* [Troubleshoot Mobile Services .NET backend]
Learn how to diagnose and fix issues that can arise with a Mobile Services .NET backend.
[Getting started with Mobile Services]:#getting-started
[Create a new mobile service]:#create-new-service
[Define the mobile service instance]:#define-mobile-service-instance
[Next Steps]:#next-steps
[0]: ./media/mobile-services-dotnet-backend-ios-get-started/mobile-quickstart-completed-ios.png
[1]: ./media/mobile-services-dotnet-backend-ios-get-started/mobile-quickstart-steps-vs.png
[6]: ./media/mobile-services-dotnet-backend-ios-get-started/mobile-portal-quickstart-ios.png
[7]: ./media/mobile-services-dotnet-backend-ios-get-started/mobile-quickstart-steps-ios.png
[8]: ./media/mobile-services-dotnet-backend-ios-get-started/mobile-xcode-project.png
[10]: ./media/mobile-services-dotnet-backend-ios-get-started/mobile-quickstart-startup-ios.png
[11]: ./media/mobile-services-dotnet-backend-ios-get-started/mobile-data-tab.png
[12]: ./media/mobile-services-dotnet-backend-ios-get-started/mobile-data-browse.png
[Get started with offline data sync]: mobile-services-ios-get-started-offline-data.md
[Add authentication to an existing app]: mobile-services-dotnet-backend-ios-get-started-users.md
[Add push notifications to an existing app]: mobile-services-dotnet-backend-ios-get-started-push.md
[Troubleshoot Mobile Services .NET backend]: mobile-services-dotnet-backend-how-to-troubleshoot.md
[Mobile Services iOS SDK]: https://go.microsoft.com/fwLink/p/?LinkID=266533
[XCode]: https://go.microsoft.com/fwLink/p/?LinkID=266532
[JavaScript backend version]: mobile-services-ios-get-started.md
================================================
FILE: docs/mobile-services-dotnet-backend-ios-push-notifications-app-users.md
================================================
# Send push notifications to authenticated users
> [AZURE.SELECTOR-LIST (Platform | Backend)]
- [(iOS | JavaScript)](mobile-services-javascript-backend-ios-push-notifications-app-users.md)
- [(Windows 8.x Store C# | .NET)](mobile-services-dotnet-backend-windows-store-dotnet-push-notifications-app-users.md)
- [(Windows 8.x Store C# | JavaScript)](mobile-services-javascript-backend-windows-store-dotnet-push-notifications-app-users.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
In this topic, you learn how to send push notifications to an authenticated user on iOS. Before starting this tutorial, complete [Get started with authentication] and [Get started with push notifications] first.
In this tutorial, you require users to authenticate first, register with the notification hub for push notifications, and update server scripts to send those notifications to only authenticated users.
## Update service to require authentication to register
1. In Solution Explorer in Visual Studio, expand the App_Start folder and open the WebApiConfig.cs project file.
2. Add the following line of code to the Register method after the **ConfigOptions** definition:
options.PushAuthorization =
Microsoft.WindowsAzure.Mobile.Service.Security.AuthorizationLevel.User;
This enforces user authentication before registering for push notifications.
2. Right-click the project, click **Add** then click **Class...**.
3. Name the new empty class `PushRegistrationHandler` then click **Add**.
4. At the top of the code page, add the following **using** statements:
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Controllers;
using Microsoft.WindowsAzure.Mobile.Service;
using Microsoft.WindowsAzure.Mobile.Service.Notifications;
using Microsoft.WindowsAzure.Mobile.Service.Security;
5. Replace the existing **PushRegistrationHandler** class with the following code:
public class PushRegistrationHandler : INotificationHandler
{
public Task Register(ApiServices services, HttpRequestContext context,
NotificationRegistration registration)
{
try
{
// Perform a check here for user ID tags, which are not allowed.
if(!ValidateTags(registration))
{
throw new InvalidOperationException(
"You cannot supply a tag that is a user ID.");
}
// Get the logged-in user.
var currentUser = context.Principal as ServiceUser;
// Add a new tag that is the user ID.
registration.Tags.Add(currentUser.Id);
services.Log.Info("Registered tag for userId: " + currentUser.Id);
}
catch(Exception ex)
{
services.Log.Error(ex.ToString());
}
return Task.FromResult(true);
}
private bool ValidateTags(NotificationRegistration registration)
{
// Create a regex to search for disallowed tags.
System.Text.RegularExpressions.Regex searchTerm =
new System.Text.RegularExpressions.Regex(@"facebook:|google:|twitter:|microsoftaccount:",
System.Text.RegularExpressions.RegexOptions.IgnoreCase);
foreach (string tag in registration.Tags)
{
if (searchTerm.IsMatch(tag))
{
return false;
}
}
return true;
}
public Task Unregister(ApiServices services, HttpRequestContext context,
string deviceId)
{
// This is where you can hook into registration deletion.
return Task.FromResult(true);
}
}
The **Register** method is called during registration. This lets you add a tag to the registration that is the ID of the logged-in user. The supplied tags are validated to prevent a user from registering for another user's ID. When a notification is sent to this user, it is received on this and any other device registered by the user.
6. Expand the Controllers folder, open the TodoItemController.cs project file, locate the **PostTodoItem** method and replace the line of code that calls **SendAsync** with the following code:
// Get the logged-in user.
var currentUser = this.User as ServiceUser;
// Use a tag to only send the notification to the logged-in user.
var result = await Services.Push.SendAsync(message, currentUser.Id);
7. Republish the mobile service project.
Now, the service uses the user ID tag to send a push notification (with the text of the inserted item) to all registrations created by the logged-in user.
## Update app to sign in before registration
Next, you need to change the way that push notifications are registered so that a user is authenticated before registration is attempted.
1. In **QSAppDelegate.m**, remove the implementation of **didFinishLaunchingWithOptions** altogether.
2. Open **QSTodoListViewController.m** and add the following code to the end of the **viewDidLoad** method:
```
// Register for remote notifications
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound];
```
## Test app
1. Press **Run** to start the app on a physical iOS device. In the app, add a new item, such as _A new Mobile Services task_, to the todo list.
2. Verify that a notification is received. Additionally -- and optionally -- repeat the above steps on a different physical iOS device, once using the same log-in account and another time using a different log-in account. Verify that notifications are received only by devices authenticating with the same user account.
[Updating the service to require authentication for registration]: #register
[Updating the app to log in before registration]: #update-app
[Testing the app]: #test
[Next Steps]:#next-steps
[Get started with authentication]: mobile-services-dotnet-backend-ios-get-started-users.md
[Get started with push notifications]: mobile-services-dotnet-backend-ios-get-started-push.md
[Mobile Services .NET How-to Conceptual Reference]: https://azure.microsoft.com/develop/mobile/how-to-guides/work-with-net-client-library
================================================
FILE: docs/mobile-services-dotnet-backend-schedule-recurring-tasks.md
================================================
# Schedule recurring jobs in Mobile Services
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
> [AZURE.SELECTOR]
- [.NET backend](mobile-services-dotnet-backend-schedule-recurring-tasks.md)
- [Javascript backend](mobile-services-schedule-recurring-tasks.md)
This topic shows you how to use the job scheduler functionality in the Azure classic portal to define server script code that is executed based on a schedule that you define. In this case, the script periodically check with a remote service, in this case Twitter, and stores the results in a new table. Some other periodic tasks that can be scheduled include:
+ Archiving old or duplicate data records.
+ Requesting and storing external data, such as tweets, RSS entries, and location information.
+ Processing or resizing stored images.
This tutorial walks you through how to use the job scheduler to create a scheduled job that requests tweet data from Twitter and stores the tweets in a new Updates table.
>[AZURE.NOTE]This tutorial uses the third-party LINQ to Twitter library to simplify OAuth 2.0 access to Twitter v1.1. APIs. You must download and install the LINQ to Twitter NuGet package to complete this tutorial. For more information, see the [LINQ to Twitter CodePlex project].
## Register for access to Twitter v1.1 APIs and store credentials
The new Twitter v1.1 APIs requires your app to authenticate before accessing resources. First, you need to get the credentials needed to request access by using OAuth 2.0. Then, you will store them securely in the app settings for your mobile service.
1. If you haven't already done so, complete the steps in the topic [Register your apps for Twitter login with Mobile Services](./
mobile-services-how-to-register-twitter-authentication.md).
Twitter generates the credentials needed to enable you to access Twitter v1.1 APIs. You can get these credentials from the Twitter Developers website.
2. Navigate to the [Twitter Developers](http://go.microsoft.com/fwlink/p/?LinkId=268300) website, sign-in with your Twitter account credentials and select your Twitter app.
3. In the **Keys and Access Tokens** tab for the app, make a note of the following values:
+ **Consumer key**
+ **Consumer secret**
+ **Access token**
+ **Access token secret**
4. Log on to the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services**, and then click your mobile service.
5. Click the **Identity** tab, enter the **Consumer key** and **Consumer secret** values obtained from Twitter, and click **Save**.

2. Click the **Configure** tab, scroll down to **App settings** and enter a **Name** and **Value** pair for each of the following that you obtained from the Twitter site, then click **Save**.
+ `TWITTER_ACCESS_TOKEN`
+ `TWITTER_ACCESS_TOKEN_SECRET`

This stores the Twitter access token in app settings. Like the consumer credentials on the **Identity** tab, the access credentials are also stored encrypted in app settings, and you can access them in your server scripts without hard-coding them in the script file. For more information, see [App settings].
[Mobile Services server script reference]: http://go.microsoft.com/fwlink/?LinkId=262293
[Register your apps for Twitter login with Mobile Services]: ./
mobile-services-how-to-register-twitter-authentication.md
[Twitter Developers]: http://go.microsoft.com/fwlink/p/?LinkId=268300
[App settings]: http://msdn.microsoft.com/library/azure/b6bb7d2d-35ae-47eb-a03f-6ee393e170f7
7. In Solution Explorer in Visual Studio, open the web.config file for the mobile service project, locate the `MS_TwitterConsumerKey` and `MS_TwitterConsumerSecret` app settings and replace the values of these keys with Twitter consumer key and consumer secret values that you set in the portal.
8. In the same section, add the following new app settings, replacing the placeholders with the Twitter access token and access token secret values that you set as app settings in the portal:
The mobile service uses these stored settings when it runs on the local computer, which lets you test the scheduled job before you publish it. When running in Azure, the mobile service instead uses values set in the portal and ignores these project settings.
## Download and install the LINQ to Twitter library
1. In **Solution Explorer** in Visual Studio, right-click the project name, and then select **Manage NuGet Packages**.
2. In the left pane, select the **Online** category, search for `linq2twitter`, click **Install** on the **linqtotwitter** package, then read and accept the license agreements.
![][1]
This adds the Linq to Twitter library to your mobile service project.
Next, you need to create a new table in which to store tweets.
## Create the new Updates table
1. In the Solution Explorer in Visual Studio, right-click the DataObjects folder, expand **Add**, click **Class**, type `Updates` for **Name**, then click **Add**.
This creates a new project file for the Updates class.
2. Right-click **References** > **Add Reference...** > **Framework** under **Assemblies**, then check **System.ComponentModel.DataAnnotations** and click **OK**.
![][7]
This adds a new assembly reference.
2. In this new class, add the following **using** statements:
using Microsoft.WindowsAzure.Mobile.Service;
using System.ComponentModel.DataAnnotations;
3. Replace the **Updates** class definition with the following code:
public class Updates
{
[Key]
public int UpdateId { get; set; }
public long TweetId { get; set; }
public string Text { get; set; }
public string Author { get; set; }
public DateTime Date { get; set; }
}
4. Expand the Models folder, open the data model context file (named *service_name*Context.cs) and add the following property that returns a typed **DbSet**:
public DbSet Updates { get; set; }
The Updates table, which is created in the database when the DbSet is first accessed, is used by the service to store tweet data.
>[AZURE.NOTE] When using the default database initializer, Entity Framework will drop and recreate the database whenever it detects a data model change in the Code First model definition. To make this data model change and maintain existing data in the database, you must use Code First Migrations. The default initializer cannot be used against a SQL Database in Azure. For more information, see [How to Use Code First Migrations to Update the Data Model](mobile-services-dotnet-backend-use-code-first-migrations.md).
Next, you create the scheduled job that accesses Twitter and stores tweet data in the new Updates table.
## Create a new scheduled job
1. Expand the ScheduledJobs folder and open the SampleJob.cs project file.
This class, which inherits from **ScheduledJob**, represents a job that can be scheduled, in the Azure classic portal, to run on a fixed schedule or on demand.
2. Replace the contents of SampleJob.cs with the following code:
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using Microsoft.WindowsAzure.Mobile.Service;
using Microsoft.WindowsAzure.Mobile.Service.ScheduledJobs;
using LinqToTwitter;
using todolistService.Models;
using todolistService.DataObjects;
namespace todolistService
{
// A simple scheduled job which can be invoked manually by submitting an HTTP
// POST request to the path "/jobs/sample".
public class SampleJob : ScheduledJob
{
private todolistContext context;
private string accessToken;
private string accessTokenSecret;
protected override void Initialize(ScheduledJobDescriptor scheduledJobDescriptor,
CancellationToken cancellationToken)
{
base.Initialize(scheduledJobDescriptor, cancellationToken);
// Create a new context with the supplied schema name.
context = new todolistContext();
}
public async override Task ExecuteAsync()
{
// Try to get the stored Twitter access token from app settings.
if (!(Services.Settings.TryGetValue("TWITTER_ACCESS_TOKEN", out accessToken) |
Services.Settings.TryGetValue("TWITTER_ACCESS_TOKEN_SECRET", out accessTokenSecret)))
{
Services.Log.Error("Could not retrieve Twitter access credentials.");
}
// Create a new authorizer to access Twitter v1.1 APIs
// using single-user OAUth 2.0 credentials.
MvcAuthorizer auth = new MvcAuthorizer();
SingleUserInMemoryCredentialStore store =
new SingleUserInMemoryCredentialStore()
{
ConsumerKey = Services.Settings.TwitterConsumerKey,
ConsumerSecret = Services.Settings.TwitterConsumerSecret,
OAuthToken = accessToken,
OAuthTokenSecret = accessTokenSecret
};
// Set the credentials for the authorizer.
auth.CredentialStore = store;
// Create a new LINQ to Twitter context.
TwitterContext twitter = new TwitterContext(auth);
// Get the ID of the most recent stored tweet.
long lastTweetId = 0;
if (context.Updates.Count() > 0)
{
lastTweetId = (from u in context.Updates
orderby u.TweetId descending
select u).Take(1).SingleOrDefault()
.TweetId;
}
// Execute a search that returns a filtered result.
var response = await (from s in twitter.Search
where s.Type == SearchType.Search
&& s.Query == "%23mobileservices"
&& s.SinceID == Convert.ToUInt64(lastTweetId + 1)
&& s.ResultType == ResultType.Recent
select s).SingleOrDefaultAsync();
// Remove retweets and replies and log the number of tweets.
var filteredTweets = response.Statuses
.Where(t => !t.Text.StartsWith("RT") && t.InReplyToUserID == 0);
Services.Log.Info("Fetched " + filteredTweets.Count()
+ " new tweets from Twitter.");
// Store new tweets in the Updates table.
foreach (Status tweet in filteredTweets)
{
Updates newTweet =
new Updates
{
TweetId = Convert.ToInt64(tweet.StatusID),
Text = tweet.Text,
Author = tweet.User.Name,
Date = tweet.CreatedAt
};
context.Updates.Add(newTweet);
}
await context.SaveChangesAsync();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
context.Dispose();
}
}
}
}
In the above code, you must replace the strings _todolistService_ and _todolistContext_ with the namespace and DbContext of your downloaded project, which are *mobile_service_name*Service and *mobile_service_name*Context, respective.
In the above code, the **ExecuteAsync** override method calls the Twitter query API using stored credentials to request recent tweets that contain the hashtag `#mobileservices`. Duplicate tweets and replies are removed from the results before they are stored in the table.
## Test the scheduled job locally
Schedule jobs can be tested locally before being published to Azure and registered in the portal.
1. In Visual Studio, with the mobile service project set as the startup project, press F5.
This starts the mobile service project and displays a new browser window with the welcome page.
2. Click **try it out**, then click **POST jobs/{jobName}**.
![][8]
4. Click **try this out**, type `Sample` as the **{jobName}** parameter value, then click **Send**.
![][9]
This sends a new POST request to the Sample job endpoint. In the local service, the **ExecuteAsync** method is started. You can set a break point in this method to debug the code.
3. In Server Explorer, expand **Data Connections**, **MSTableConnectionString**, and **tables**; right-click **Updates** and click **Show Table Data**.
The new tweets are entered as rows in the data table.
## Publish the service and register the new job
The job must be registered in the **Scheduler** tab so that Mobile Services can run it on the schedule that you define.
3. Republish the mobile service project to Azure.
4. In the [Azure classic portal], click Mobile Services, and then click your app.
2. Click the **Scheduler** tab, then click **+Create**.
>[AZURE.NOTE]When you run your mobile service in Free tier, you are only able to run one scheduled job at a time. In paid tiers, you can run up to ten scheduled jobs at a time.
3. In the scheduler dialog, enter _Sample_ for the **Job Name**, set the schedule interval and units, then click the check button.
![][4]
This creates a new job named **Sample**.
4. Click the new job you just created, then click **Run Once** to test the script.
This executes the job while it remains disabled in the scheduler. From this page, you can enable the job and change its schedule at any time.
>[AZURE.NOTE]A POST request can still be used to start the scheduled job. However, the authorization defaults to user, which means that the request must include the application key in the header.
4. (Optional) In the [Azure classic portal], click manage for the database associated with your mobile service.
![][6]
5. In the Azure classic portal, execute a query to view the changes made by the app. Your query will be similar to the following query but use your mobile service name as schema name instead of `todolist`.
SELECT * FROM [todolist].[Updates]
Congratulations, you have successfully created a new scheduled job in your mobile service. This job will be executed as scheduled until you disable or modify it.
[Register for Twitter access and store credentials]: #get-oauth-credentials
[Download and install the LINQ to Twitter library]: #install-linq2twitter
[Create the new Updates table]: #create-table
[Create a new scheduled job]: #add-job
[Test the scheduled job locally]: #run-job-locally
[Publish the service and register the job]: #register-job
[Next steps]: #next-steps
[1]: ./media/mobile-services-dotnet-backend-schedule-recurring-tasks/add-linq2twitter-nuget-package.png
[2]: ./media/mobile-services-dotnet-backend-schedule-recurring-tasks/mobile-services-selection.png
[3]: ./media/mobile-services-dotnet-backend-schedule-recurring-tasks/mobile-schedule-new-job-cli.png
[4]: ./media/mobile-services-dotnet-backend-schedule-recurring-tasks/create-new-job.png
[5]: ./media/mobile-services-dotnet-backend-schedule-recurring-tasks/sample-job-run-once.png
[6]: ./media/mobile-services-dotnet-backend-schedule-recurring-tasks/manage-sql-azure-database.png
[7]: ./media/mobile-services-dotnet-backend-schedule-recurring-tasks/add-component-model-reference.png
[8]: ./media/mobile-services-dotnet-backend-schedule-recurring-tasks/mobile-service-start-page.png
[9]: ./media/mobile-services-dotnet-backend-schedule-recurring-tasks/mobile-service-try-this-out.png
[Azure classic portal]: https://manage.windowsazure.com/
[Register your apps for Twitter login with Mobile Services]: mobile-services-how-to-register-twitter-authentication.md
[Twitter Developers]: http://go.microsoft.com/fwlink/p/?LinkId=268300
[App settings]: http://msdn.microsoft.com/library/windowsazure/b6bb7d2d-35ae-47eb-a03f-6ee393e170f7
[LINQ to Twitter CodePlex project]: http://linqtotwitter.codeplex.com/
================================================
FILE: docs/mobile-services-dotnet-backend-service-side-authorization.md
================================================
# Service-side authorization of users in Mobile Services
> [AZURE.SELECTOR]
- [.NET backend](mobile-services-dotnet-backend-service-side-authorization.md)
- [Javascript backend](mobile-services-javascript-backend-service-side-authorization.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This topic shows you how to use server-side logic to authorize users. In this tutorial, you modify table controllers, filter queries based on user IDs, and give users access to only their own data. Filtering a user's query results by the user ID is the most basic form of authorization. Depending on your specific scenario, you might also want to create Users or Roles tables to track more detailed user authorization information, such as which endpoints a given user is permitted to access.
This tutorial is based on the Mobile Services Quick Start and builds on the [Add Authentication to Existing Mobile Services App] tutorial. Please complete [Add Authentication to Existing Mobile Services App] first.
## Modify data access methods
1. In Visual Studio, open your mobile project, expand the DataObjects folder, and open **TodoItem.cs**. The **TodoItem** class defines the data object, and you need to add a **UserId** property to use for filtering. Add the following new UserId property to the **TodoItem** class:
public string UserId { get; set; }
>[AZURE.NOTE] To make this data model change and maintain existing data in the database, you must use [Code First Migrations](mobile-services-dotnet-backend-how-to-use-code-first-migrations.md).
2. In Visual Studio, expand the Controllers folder, open **TodoItemController.cs** and add the following using statement:
using Microsoft.WindowsAzure.Mobile.Service.Security;
3. Locate the **PostTodoItem** method and add the following code at the beginning of the method.
// Get the logged in user
var currentUser = User as ServiceUser;
// Set the user ID on the item
item.UserId = currentUser.Id;
This code adds the user ID of the authenticated user to the item, before it is inserted into the TodoItem table.
3. Locate the **GetAllTodoItems** method and replace the existing **return** statement with the following line of code:
// Get the logged in user
var currentUser = User as ServiceUser;
return Query().Where(todo => todo.UserId == currentUser.Id);
This query filters the returned TodoItem objects so that each user only receives the items that they inserted.
4. Republish the mobile service project to Azure.
## Test the app
1. Notice that when you now run your client-side app, although there are items already in the database from previous tutorials, no items are returned. This happens because previous items were inserted without the user ID column and now have null values.
2. If you have additional login accounts, verify that users can only see their own data by closing and deleting the app and running it again. When the login credentials dialog is displayed, enter a different login and verify that the items entered under the previous login are not displayed.
[Register server scripts]: #register-scripts
[Next Steps]:#next-steps
[3]: ./media/mobile-services-dotnet-backend-ios-authorize-users-in-scripts/mobile-quickstart-startup-ios.png
[Add Authentication to Existing Mobile Services App]: mobile-services-dotnet-backend-ios-get-started-users.md
================================================
FILE: docs/mobile-services-dotnet-backend-store-code-source-control.md
================================================
# Store your mobile service project code in source control
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
> [AZURE.SELECTOR]
- [.NET backend](mobile-services-dotnet-backend-store-code-source-control.md)
- [Javascript backend](mobile-services-store-scripts-source-control.md)
This topic shows you how to use the source control provided by Azure Mobile Services to store your .NET backend service project. Your project can be published by simply uploading from your local Git repository to your production mobile service.
To complete this tutorial, you must have already created a mobile service by completing either the [Get started with Mobile Services] tutorial.
## Enable source control in your mobile service
To be able to store app data in the new mobile service, you must first create a new table in the associated SQL Database instance.
1. Log on to the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services**, click your mobile service, then click the **Dashboard** tab.
2. (Optional) If you have already set the Mobile Services or Websites source control credentials for your Azure subscription, then you can skip down to step 4. Otherwise, click **Set up source control** under **Quick glance** and click **Yes** to confirm.

3. Supply a **User name**, **New password**, confirm the password, then click the check button.
The Git repository is created in your mobile service. Make a note of the credentials you just supplied; you will use them to access this and other Mobile Services repositories in your subscription.
4. Click the **Configure** tab and notice the **Source control** fields.

The URL of the Git repository is displayed. You will use this URL to clone the repository to your local computer.
With source control enabled in your mobile service, you can use Git to clone the repository to your local computer.
## Install Git and create the local repository
1. Install Git on your local computer.
The steps required to install Git vary between operating systems. See [Installing Git] for operating system specific distributions and installation guidance.
> [AZURE.NOTE]
> On some operating systems, both a command-line and GUI version of Git are available. The instructions provided in this article use the command-line version.
2. Open a command-line, such as **GitBash** (Windows) or **Bash** (Unix Shell). On OS X systems you can access the command-line through the **Terminal** application.
3. From the command line, change to the directory where you will store your scripts. For example, `cd SourceControl`.
4. Use the following command to create a local copy of your new Git repository, replacing `` with the URL of the Git repository for your mobile service:
git clone
5. When prompted, type in the user name and password that you set when you enabled source control in your mobile service. After successful authentication, you will see a series of responses like this:
remote: Counting objects: 8, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 8 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (8/8), done.
6. Browse to the directory from which you ran the `git clone` command, and notice that a new directory is created with the name of the mobile service. For a .NET backend mobile service, the git repository is initial empty.
Now that you have created your local repository, you can publish your .NET backend service project from this repository.
## Publish your project by using Git
1. Create a new .NET backend mobile service project in Visual Studio 2013, or move an existing project into your new local repository.
For a quick test, download and save the Mobile Services quickstart project to this folder.
2. Remove any NuGet package folders, leaving the packages.config file.
Mobile Services will automatically restore your NuGet packages based on the packages.confign file. You can also define a .gitignore file to prevent the package directories from being added.
3. In the Git command prompt, type the following command to start tracking the new script file:
$ git add .
4. Type the following command to commit changes:
$ git commit -m "adding the .NET backend service project"
5. Type the following command to upload the changes to the remote repository, and supply your credentials:
$ git push origin master
You should see a series of commands that indicates that the project is deployed to Mobile Services, packages are added, and the service is restarted.
6. Browse to the URL of your .NET backend mobile service, and you should see the following:

Now, your mobile service project is maintained in source control, and you can publish service updates by simply pushing updates from your local repository. For information about making data model changes in a .NET backend mobile service that uses a SQL Database, see [How to make data model changes to a .NET backend mobile service].
[Git website]: http://git-scm.com
[Source control]: http://msdn.microsoft.com/library/windowsazure/c25aaede-c1f0-4004-8b78-113708761643
[Installing Git]: http://git-scm.com/book/en/Getting-Started-Installing-Git
[Get started with Mobile Services]: mobile-services-dotnet-backend-ios-get-started.md
[How to make data model changes to a .NET backend mobile service]: mobile-services-dotnet-backend-how-to-use-code-first-migrations.md
================================================
FILE: docs/mobile-services-dotnet-backend-store-data-table-storage.md
================================================
# Build a .NET backend mobile service that uses Table storage
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This topic shows you how to use a non-relational data store for your .NET backend mobile service. In this tutorial, you will modify the Azure Mobile Services quickstart project to use Azure Table storage instead of the default Azure SQL Database data store.
The tutorial requires completion of the [Get started with Mobile Services] tutorial. You will also need an Azure storage account.
## Configure Azure Table storage in your .NET backend mobile service
First, you need to configure your mobile service and .NET backend code project to connect to Azure storage.
1. In **Solution Explorer** in Visual Studio, right-click the .NET backend project, and then select **Manage NuGet Packages**.
2. In the left pane, select the **Online** category, select **Stabile Only**, search for **MobileServices**, click **Install** on the **Microsoft Azure Mobile Services .NET Backend Azure Storage Extension** package, then accept the license agreements.

This adds support for Azure storage services to the .NET backend mobile service project.
3. If you haven't yet created your storage account, see [How To Create a Storage Account](https://azure.microsoft.com/en-us/documentation/articles/storage-create-storage-account/).
4. In the [Azure classic portal], click **Storage**, click the storage account, then click **Manage Keys**.
5. Make a note of the **Storage Account Name** and **Access Key**.
6. In your mobile service, click the **Configure** tab, scroll down to **Connection strings** and enter a new connection string with a **Name** of `StorageConnectionString` and a **Value** that is your storage account connection string in the following format.
DefaultEndpointsProtocol=https;AccountName=;AccountKey=;

7. In the above string, replace the values of `` and `` with the values from the portal, then click **Save**.
The storage account connection string is stored encrypted in app settings. You can access this string in any table controller at runtime.
8. In Solution Explorer in Visual Studio, open the Web.config file for the mobile service project and add the following new connection string:
9. Replace the `` placeholder with the connection string from step 6.
The mobile service uses this connection string when it runs on your local computer, which lets you test the code before you publish it. When running in Azure, the mobile service instead uses the connection string value set in the portal and ignores the connection string in the project.
## Modify data types and table controllers
Because the TodoList quickstart project is designed to work with a SQL Database using Entity Framework, you need to make some updates in the project to work with Table storage.
1. Modify the **TodoItem** data type to derive from **StorageData** instead of **EntityData**, as follows.
public class TodoItem : StorageData
{
public string Text { get; set; }
public bool Complete { get; set; }
}
>[AZURE.NOTE]The **StorageData** type has an Id property that requires a compound key that is a string in the format *partitionId*,*rowValue*.
2. In **TodoItemController**, add the following using statement.
using System.Web.Http.OData.Query;
using System.Collections.Generic;
3. Replace the **Initialize** method of the **TodoItemController** with the following.
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
// Create a new Azure Storage domain manager using the stored
// connection string and the name of the table exposed by the controller.
string connectionStringName = "StorageConnectionString";
var tableName = controllerContext.ControllerDescriptor.ControllerName.ToLowerInvariant();
DomainManager = new StorageDomainManager(connectionStringName,
tableName, Request, Services);
}
This create a new storage domain manager for the requested controller using the storage account connection string.
3. Replace the existing **GetAllTodoItems** method with the following code.
public Task> GetAllTodoItems(ODataQueryOptions options)
{
// Call QueryAsync, passing the supplied query options.
return DomainManager.QueryAsync(options);
}
Unlike a SQL Database, this version doesn't return IQueryable, so the result can be bound to but not futher composed in a query.
## Update the client app
You need to make one change on the client side to make the quickstart app work with the .NET backend using Table storage. This is due to the compound key expected by the table storage provider.
1. Open the client code file that contains the data access code and find the method where the insert operation performed.
2. Update the TodoItem instance being added to explicitly set the Id field in the string format `,`.
This is an example of how this ID might be set in a C# app, where the partition part is fixed and the row part is GUID-based.
todoItem.Id = string.Format("partition,{0}", Guid.NewGuid());
You are now ready to test the app.
## Test the application
1. (Optional) Republish your mobile service .NET backend project.
You can also test your mobile service locally before you publish the .NET backend project to Azure. Whether you test locally or in Azure, the mobile service will be using the Azure Table storage.
4. Run the quickstart client app connected to your mobile service.
Note that you do not see items that you previously added using the quickstart tutorial. This is because the Table store is currently empty.
5. Add new items to generate database changes.
The app and mobile service should behave as before, except now your data is being stored in your non-relational store instead of in the SQL Database.
## Next Steps
Now that you have seen how easy it is to use Table storage with .NET backend, consider exploring some other backend storage options:
+ [Connect to an on-premises SQL Server using Hybrid Connections](mobile-services-dotnet-backend-hybrid-connections-get-started.md)Hybrid Connections lets your mobile service securely connect to your on-premises assets. In this way, you can make your on-premises data accessible to your mobile clients by using Azure. Supported assets include any resource that runs on a static TCP port, including Microsoft SQL Server, MySQL, HTTP Web APIs, and most custom web services.
+ [Upload images to Azure Storage using Mobile Services](mobile-services-dotnet-backend-windows-universal-dotnet-upload-data-blob-storage.md)Shows you how to extend the TodoList sample project to let you upload images from your app to Azure Blob storage.
[Create a non-relational store]: #create-store
[Modify data and controllers]: #modify-service
[Test the application]: #test-application
[Get started with Mobile Services]: mobile-services-dotnet-backend-windows-store-dotnet-get-started.md
[Azure classic portal]: https://manage.windowsazure.com/
[What is the Table Service]: https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-tables/#what-is
[MongoLab Add-on Page]: /gallery/store/mongolab/mongolab
================================================
FILE: docs/mobile-services-dotnet-backend-use-existing-sql-database.md
================================================
# Build a service using an existing SQL database with the Mobile Services .NET backend
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
The Mobile Services .NET backend makes it easy to take advantage of existing assets in building a mobile service. One particularly interesting scenario is using an existing SQL database (either on-premises or in the cloud), that may already be used by other applications, to make existing data available to mobile clients. In this case it's a requirement that database model (or *schema*) remain unchanged, in order for existing solutions to continue working.
## Exploring the existing database model
For this tutorial we will use the database that was created with your mobile service, but we will not use the default model that is created. Instead, we will manually create an arbitrary model that will represent an existing application that you may have. For full details about how to connect to an on-premises database instead, check out [Connect to an on-premises SQL Server from an Azure mobile service using Hybrid Connections](mobile-services-dotnet-backend-hybrid-connections-get-started.md).
1. Start by creating a Mobile Services server project in **Visual Studio 2013 Update 2** or by using the quickstart project that you can download on the Mobile Services tab for your service in the [Azure classic portal](http://manage.windowsazure.com). For the purposes of this tutorial, we will assume your server project name is **ShoppingService**.
2. Create a **Customer.cs** file inside the **Models** folder and use the following implementation. You will need to add an assembly reference to **System.ComponentModel.DataAnnotations** to your project.
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace ShoppingService.Models
{
public class Customer
{
[Key]
public int CustomerId { get; set; }
public string Name { get; set; }
public virtual ICollection Orders { get; set; }
}
}
3. Create an **Order.cs** file inside the **Models** folder and use the following implementation:
using System.ComponentModel.DataAnnotations;
namespace ShoppingService.Models
{
public class Order
{
[Key]
public int OrderId { get; set; }
public string Item { get; set; }
public int Quantity { get; set; }
public bool Completed { get; set; }
public int CustomerId { get; set; }
public virtual Customer Customer { get; set; }
}
}
You will note that these two classes have a *relationship*: every **Order** is associated with a single **Customer** and a **Customer** can be associated with multiple **Orders**. Having relationships is common in existing data models.
4. Create an **ExistingContext.cs** file inside the **Models** folder and implement it as so:
using System.Data.Entity;
namespace ShoppingService.Models
{
public class ExistingContext : DbContext
{
public ExistingContext()
: base("Name=MS_TableConnectionString")
{
}
public DbSet Customers { get; set; }
public DbSet Orders { get; set; }
}
}
The structure above approximates an existing Entity Framework model that you may already be using for an existing application. Please note that the model is not aware of Mobile Services in any way at this stage.
## Creating data transfer objects (DTOs) for your mobile service
The data model you would like to use with your mobile service may be arbitrarily complex; it could contain hundreds of entities with a variety of relationships between them. When building a mobile app, it is usually desirable to simplify the data model and eliminate relationships (or handle them manually) in order to minimize the payload being sent back and forth between the app and the service. In this section, we will create a set of simplified objects (known as "data transfer objects" or "DTOs"), that are mapped to the data you have in your database, yet contain only the minimal set of properties needed by your mobile app.
1. Create the **MobileCustomer.cs** file in the **DataObjects** folder of your service project and use the following implementation:
using Microsoft.WindowsAzure.Mobile.Service;
namespace ShoppingService.DataObjects
{
public class MobileCustomer : EntityData
{
public string Name { get; set; }
}
}
Note that this class is similar to the **Customer** class in the model, except the relationship property to **Order** is removed. For an object to work correctly with Mobile Services offline sync, it needs a set of *system properties* for optimistic concurrency, so you will notice that the DTO inherits from [**EntityData**](http://msdn.microsoft.com/library/microsoft.windowsazure.mobile.service.entitydata.aspx), which contains those properties. The int-based **CustomerId** property from the original model is replaced by the string-based **Id** property from **EntityData**, which will be the **Id** that Mobile Services will use.
2. Create the **MobileOrder.cs** file in the **DataObjects** folder of your service project.
using Microsoft.WindowsAzure.Mobile.Service;
using Newtonsoft.Json;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace ShoppingService.DataObjects
{
public class MobileOrder : EntityData
{
public string Item { get; set; }
public int Quantity { get; set; }
public bool Completed { get; set; }
[NotMapped]
public int CustomerId { get; set; }
[Required]
public string MobileCustomerId { get; set; }
public string MobileCustomerName { get; set; }
}
}
The **Customer** relationship property has been replaced with the **Customer** name and a **MobileCustomerId** property that can be used to manually model the relationship on the client. For now you can ignore the **CustomerId** property, it is only used later on.
3. You might notice that with the addition of the system properties on the **EntityData** base class, our DTOs now have more properties than the model types. Clearly we need a place to store these properties, so we will add a few extra columns to the original database. While this does change the database, it will not break existing applications since the changes are purely additive (adding new columns to the schema). To do that, add the following statements to the top of **Customer.cs** and **Order.cs**:
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.WindowsAzure.Mobile.Service.Tables;
using System;
4. Next, add these extra properties to each of the classes:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Index]
[TableColumn(TableColumnType.CreatedAt)]
public DateTimeOffset? CreatedAt { get; set; }
[TableColumn(TableColumnType.Deleted)]
public bool Deleted { get; set; }
[Index]
[TableColumn(TableColumnType.Id)]
[MaxLength(36)]
public string Id { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
[TableColumn(TableColumnType.UpdatedAt)]
public DateTimeOffset? UpdatedAt { get; set; }
[TableColumn(TableColumnType.Version)]
[Timestamp]
public byte[] Version { get; set; }
4. The system properties just added have some built-in behaviors (for example automatic update of created/updated at) that happen transparently with database operations. To enable these behaviors, we need to make a change to **ExistingContext.cs**. At the top of the file, add the following:
using System.Data.Entity.ModelConfiguration.Conventions;
using Microsoft.WindowsAzure.Mobile.Service.Tables;
using System.Linq;
5. In the body of **ExistingContext**, override [**OnModelCreating**](http://msdn.microsoft.com/library/system.data.entity.dbcontext.onmodelcreating.aspx):
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(
new AttributeToColumnAnnotationConvention(
"ServiceTableColumn", (property, attributes) => attributes.Single().ColumnType.ToString()));
base.OnModelCreating(modelBuilder);
}
5. Let's populate the database with some example data. Open the file **WebApiConfig.cs**. Create a new [**IDatabaseInitializer**](http://msdn.microsoft.com/library/gg696323.aspx) and configure it in the **Register** method as shown below.
using Microsoft.WindowsAzure.Mobile.Service;
using ShoppingService.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Entity;
using System.Web.Http;
namespace ShoppingService
{
public static class WebApiConfig
{
public static void Register()
{
ConfigOptions options = new ConfigOptions();
HttpConfiguration config = ServiceConfig.Initialize(new ConfigBuilder(options));
Database.SetInitializer(new ExistingInitializer());
}
}
public class ExistingInitializer : ClearDatabaseSchemaIfModelChanges
{
protected override void Seed(ExistingContext context)
{
List orders = new List
{
new Order { OrderId = 10, Item = "Guitars", Quantity = 2, Id = Guid.NewGuid().ToString()},
new Order { OrderId = 20, Item = "Drums", Quantity = 10, Id = Guid.NewGuid().ToString()},
new Order { OrderId = 30, Item = "Tambourines", Quantity = 20, Id = Guid.NewGuid().ToString() }
};
List customers = new List
{
new Customer { CustomerId = 1, Name = "John", Orders = new Collection {
orders[0]}, Id = Guid.NewGuid().ToString()},
new Customer { CustomerId = 2, Name = "Paul", Orders = new Collection {
orders[1]}, Id = Guid.NewGuid().ToString()},
new Customer { CustomerId = 3, Name = "Ringo", Orders = new Collection {
orders[2]}, Id = Guid.NewGuid().ToString()},
};
foreach (Customer c in customers)
{
context.Customers.Add(c);
}
base.Seed(context);
}
}
}
## Establishing a mapping between DTOs and model
We now have the model types **Customer** and **Order** and the DTOs **MobileCustomer** and **MobileOrder**, but we need to instruct the backend to automatically transform between the two. Here Mobile Services relies on [**AutoMapper**](http://automapper.org/), an object relational mapper, which is already referenced in the project.
1. Add the following to the top of **WebApiConfig.cs**:
using AutoMapper;
using ShoppingService.DataObjects;
2. To define the mapping, add the following to the **Register** method of the **WebApiConfig** class.
Mapper.Initialize(cfg =>
{
cfg.CreateMap();
cfg.CreateMap();
cfg.CreateMap()
.ForMember(dst => dst.MobileCustomerId, map => map.MapFrom(x => x.Customer.Id))
.ForMember(dst => dst.MobileCustomerName, map => map.MapFrom(x => x.Customer.Name));
cfg.CreateMap();
});
AutoMapper will now map the objects to one another. All properties with corresponding names will be matched, for example **MobileOrder.CustomerId** will get automatically mapped to **Order.CustomerId**. Custom mappings can be configured as shown above, where we map the **MobileCustomerName** property to the **Name** property of the **Customer** relationship property.
## Implementing domain-specific logic
The next step is to implement a [**MappedEntityDomainManager**](http://msdn.microsoft.com/library/dn643300.aspx), which serves as an abstraction layer between our mapped data store and the controller which will serve HTTP traffic from our clients. We will be able to write our controller in the next section purely in terms of the DTOs and the **MappedEntityDomainManager** we add here will handle the communication with the original data store, while also giving us a place to implement any logic specific to it.
1. Add a **MobileCustomerDomainManager.cs** to the **Models** folder of your project. Paste in the following implementation:
using AutoMapper;
using Microsoft.WindowsAzure.Mobile.Service;
using ShoppingService.DataObjects;
using System.Data.Entity;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.OData;
namespace ShoppingService.Models
{
public class MobileCustomerDomainManager : MappedEntityDomainManager
{
private ExistingContext context;
public MobileCustomerDomainManager(ExistingContext context, HttpRequestMessage request, ApiServices services)
: base(context, request, services)
{
Request = request;
this.context = context;
}
public static int GetKey(string mobileCustomerId, DbSet customers, HttpRequestMessage request)
{
int customerId = customers
.Where(c => c.Id == mobileCustomerId)
.Select(c => c.CustomerId)
.FirstOrDefault();
if (customerId == 0)
{
throw new HttpResponseException(request.CreateNotFoundResponse());
}
return customerId;
}
protected override T GetKey(string mobileCustomerId)
{
return (T)(object)GetKey(mobileCustomerId, this.context.Customers, this.Request);
}
public override SingleResult Lookup(string mobileCustomerId)
{
int customerId = GetKey(mobileCustomerId);
return LookupEntity(c => c.CustomerId == customerId);
}
public override async Task InsertAsync(MobileCustomer mobileCustomer)
{
return await base.InsertAsync(mobileCustomer);
}
public override async Task UpdateAsync(string mobileCustomerId, Delta patch)
{
int customerId = GetKey(mobileCustomerId);
Customer existingCustomer = await this.Context.Set().FindAsync(customerId);
if (existingCustomer == null)
{
throw new HttpResponseException(this.Request.CreateNotFoundResponse());
}
MobileCustomer existingCustomerDTO = Mapper.Map(existingCustomer);
patch.Patch(existingCustomerDTO);
Mapper.Map(existingCustomerDTO, existingCustomer);
await this.SubmitChangesAsync();
MobileCustomer updatedCustomerDTO = Mapper.Map(existingCustomer);
return updatedCustomerDTO;
}
public override async Task ReplaceAsync(string mobileCustomerId, MobileCustomer mobileCustomer)
{
return await base.ReplaceAsync(mobileCustomerId, mobileCustomer);
}
public override async Task DeleteAsync(string mobileCustomerId)
{
int customerId = GetKey(mobileCustomerId);
return await DeleteItemAsync(customerId);
}
}
}
An important part of this class is the **GetKey** method where we indicate how to locate the ID property of the object in the original data model.
2. Add a **MobileOrderDomainManager.cs** to the **Models** folder of your project:
using AutoMapper;
using Microsoft.WindowsAzure.Mobile.Service;
using ShoppingService.DataObjects;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.OData;
namespace ShoppingService.Models
{
public class MobileOrderDomainManager : MappedEntityDomainManager
{
private ExistingContext context;
public MobileOrderDomainManager(ExistingContext context, HttpRequestMessage request, ApiServices services)
: base(context, request, services)
{
Request = request;
this.context = context;
}
protected override T GetKey(string mobileOrderId)
{
int orderId = this.context.Orders
.Where(o => o.Id == mobileOrderId)
.Select(o => o.OrderId)
.FirstOrDefault();
if (orderId == 0)
{
throw new HttpResponseException(this.Request.CreateNotFoundResponse());
}
return (T)(object)orderId;
}
public override SingleResult Lookup(string mobileOrderId)
{
int orderId = GetKey(mobileOrderId);
return LookupEntity(o => o.OrderId == orderId);
}
private async Task VerifyMobileCustomer(string mobileCustomerId, string mobileCustomerName)
{
int customerId = MobileCustomerDomainManager.GetKey(mobileCustomerId, this.context.Customers, this.Request);
Customer customer = await this.context.Customers.FindAsync(customerId);
if (customer == null)
{
throw new HttpResponseException(Request.CreateBadRequestResponse("Customer with name '{0}' was not found", mobileCustomerName));
}
return customer;
}
public override async Task InsertAsync(MobileOrder mobileOrder)
{
Customer customer = await VerifyMobileCustomer(mobileOrder.MobileCustomerId, mobileOrder.MobileCustomerName);
mobileOrder.CustomerId = customer.CustomerId;
return await base.InsertAsync(mobileOrder);
}
public override async Task UpdateAsync(string mobileOrderId, Delta patch)
{
Customer customer = await VerifyMobileCustomer(patch.GetEntity().MobileCustomerId, patch.GetEntity().MobileCustomerName);
int orderId = GetKey(mobileOrderId);
Order existingOrder = await this.Context.Set().FindAsync(orderId);
if (existingOrder == null)
{
throw new HttpResponseException(this.Request.CreateNotFoundResponse());
}
MobileOrder existingOrderDTO = Mapper.Map(existingOrder);
patch.Patch(existingOrderDTO);
Mapper.Map(existingOrderDTO, existingOrder);
// This is required to map the right Id for the customer
existingOrder.CustomerId = customer.CustomerId;
await this.SubmitChangesAsync();
MobileOrder updatedOrderDTO = Mapper.Map(existingOrder);
return updatedOrderDTO;
}
public override async Task ReplaceAsync(string mobileOrderId, MobileOrder mobileOrder)
{
await VerifyMobileCustomer(mobileOrder.MobileCustomerId, mobileOrder.MobileCustomerName);
return await base.ReplaceAsync(mobileOrderId, mobileOrder);
}
public override Task DeleteAsync(string mobileOrderId)
{
int orderId = GetKey(mobileOrderId);
return DeleteItemAsync(orderId);
}
}
}
In this case the **InsertAsync** and **UpdateAsync** methods are interesting; that's where we enforce the relationship that each **Order** must have a valid associated **Customer**. In **InsertAsync** you'll notice that we populate the **MobileOrder.CustomerId** property, which maps to the **Order.CustomerId** property. We get that value based by looking up the **Customer** with the matching **MobileOrder.MobileCustomerId**. This is because by default the client is only aware of the Mobile Services ID (**MobileOrder.MobileCustomerId**) of the **Customer**, which is different than its actual primary key needed to set the foreign key (**MobileOrder.CustomerId**) from **Order** to **Customer**. This is only used internally within the service to facilitate the insert operation.
We are now ready to create controllers to expose our DTOs to our clients.
## Implementing a TableController using DTOs
1. In the **Controllers** folder, add the file **MobileCustomerController.cs**:
using Microsoft.WindowsAzure.Mobile.Service;
using Microsoft.WindowsAzure.Mobile.Service.Security;
using ShoppingService.DataObjects;
using ShoppingService.Models;
using System.Linq;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.OData;
namespace ShoppingService.Controllers
{
public class MobileCustomerController : TableController
{
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
var context = new ExistingContext();
DomainManager = new MobileCustomerDomainManager(context, Request, Services);
}
public IQueryable GetAllMobileCustomers()
{
return Query();
}
public SingleResult GetMobileCustomer(string id)
{
return Lookup(id);
}
[AuthorizeLevel(AuthorizationLevel.Admin)]
protected override Task PatchAsync(string id, Delta patch)
{
return base.UpdateAsync(id, patch);
}
[AuthorizeLevel(AuthorizationLevel.Admin)]
protected override Task PostAsync(MobileCustomer item)
{
return base.InsertAsync(item);
}
[AuthorizeLevel(AuthorizationLevel.Admin)]
protected override Task DeleteAsync(string id)
{
return base.DeleteAsync(id);
}
}
}
You will note the use of the AuthorizeLevel attribute to restrict public access to the Insert/Update/Delete operations on the controller. For the purposes of this scenario, the list of Customers will be read-only, but we will allow the creation of new Orders and associating them with existing customers.
2. In the **Controllers** folder, add the file **MobileOrderController.cs**:
using Microsoft.WindowsAzure.Mobile.Service;
using ShoppingService.DataObjects;
using ShoppingService.Models;
using System.Linq;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Description;
using System.Web.Http.OData;
namespace ShoppingService.Controllers
{
public class MobileOrderController : TableController
{
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
ExistingContext context = new ExistingContext();
DomainManager = new MobileOrderDomainManager(context, Request, Services);
}
public IQueryable GetAllMobileOrders()
{
return Query();
}
public SingleResult GetMobileOrder(string id)
{
return Lookup(id);
}
public Task PatchMobileOrder(string id, Delta patch)
{
return UpdateAsync(id, patch);
}
[ResponseType(typeof(MobileOrder))]
public async Task PostMobileOrder(MobileOrder item)
{
MobileOrder current = await InsertAsync(item);
return CreatedAtRoute("Tables", new { id = current.Id }, current);
}
public Task DeleteMobileOrder(string id)
{
return DeleteAsync(id);
}
}
}
3. You are now ready to run your service. Press **F5** and use the test client built into the help page to modify the data.
Please note that both controller implementations make exclusive use of the DTOs **MobileCustomer** and **MobileOrder** and are agnostic of the underlying model. These DTOs are readily serialized to JSON and can be used to exchange data with the Mobile Services client SDK on all platforms. For example, building a Windows Store app, the corresponding client-side type would look as shown below. The type would be analogous on other client platforms.
using Microsoft.WindowsAzure.MobileServices;
using System;
namespace ShoppingClient
{
public class MobileCustomer
{
public string Id { get; set; }
public string Name { get; set; }
[CreatedAt]
public DateTimeOffset? CreatedAt { get; set; }
[UpdatedAt]
public DateTimeOffset? UpdatedAt { get; set; }
public bool Deleted { get; set; }
[Version]
public string Version { get; set; }
}
}
As a next step, you can now build out the client app to access the service.
================================================
FILE: docs/mobile-services-dotnet-backend-windows-store-dotnet-aad-rbac.md
================================================
# Role Based Access Control in Mobile Services using JavaScript and the Azure Active Directory
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
> [AZURE.SELECTOR-LIST (Platform | Backend)]
- [(Windows 8.x Store C# | .NET)](mobile-services-dotnet-backend-windows-store-dotnet-aad-rbac.md)
## Overview
Roles-based access control (RBAC) is the practice of assigning permissions to roles that your users can hold. It nicely defines boundaries on what certain classes of users can and cannot do. This tutorial will walk you through how to add basic RBAC to Azure Mobile Services.
This tutorial will demonstrate role based access control, checking each user's membership to a Sales group defined in the Azure Active Directory (AAD). The access check will be done with .NET Mobile Service backend using the [Graph REST API] for Azure Active Directory. Only users who belong to the Sales group will be allowed to query the data.
>[AZURE.NOTE] The intent of this tutorial is to extend your knowledge of authentication to include authorization practices. It is expected that you first complete the [Add Authentication to your app] tutorial using the Azure Active Directory authentication provider. This tutorial continues to update the TodoItem application used in the [Add Authentication to your app] tutorial.
## Prerequisites
This tutorial requires the following:
* Visual Studio 2013 running on Windows 8.1.
* Completion of the [Add Authentication to your app] tutorial using the Azure Active Directory authentication provider.
## Generate a key for the Integrated Application
During the [Add Authentication to your app] tutorial, you created a registration for the integrated application when you completed the [Register to use an Azure Active Directory Login] step. In this section you generate a key to be used when reading directory information with that integrated application's client ID.
1. Click **Applications** tab on your directory page in the [Azure classic portal](https://manage.windowsazure.com/).
2. Click your integrated application registration.
3. Click **Configure** on the application page and scroll down the the **keys** section of the page.
4. Click **1 year** duration for a new key. Then click **Save** and the portal will display your new key value.
5. Copy the **Client ID** and **Key** shown after you save. Note that the key value will only be shown to you a single time after you have saved.

6. Scroll down to the bottom of the integrated application configuration page and enable the **Read directory data** permission for the application and click **Save**.

7. In the [Azure classic portal](https://manage.windowsazure.com/), navigate back to your mobile service and click the **Configure** tab. Scroll down to the **app settings** section and add the following app settings and click **Save**.
App Setting Name
Description
AAD_CLIENT_ID
The client id you copied from your integrated app in the steps above.
AAD_CLIENT_KEY
The app key you generated in your AAD integrated app in the steps above.
AAD_TENANT_DOMAIN
Your AAD domain name. Should be similar to "mydomain.onmicrosoft.com"

## Create a Sales group with membership
In this section you add two new users to your directory along with the new Sales group. One of the users will be granted membership to the sales group. The other user will not be granted membership to the group.
### Create the users
1. In the [Azure classic portal](https://manage.windowsazure.com) navigate to the directory that you previously configured for authentication when you completed the tutorial to add authentication to your app.
2. Click **Users** at the top of the page. Then click the **Add User** button at the bottom.
3. Complete the new user dialogs creating to create a user named **Bob**. Note the temporary password for the user.
4. Create another user named **Dave**. Note the temporary password for the user.
5. The new users should look similar to what is shown below.

### Create the Sales group
1. On the directory page, click **Groups** at the top of the page. Then click the **Add Group** button at the bottom.
2. Enter **Sales** for the name of the group and press the complete button on the dialog to create the group.

### Add user membership to the Sales group.
1. Click **Groups** at the top of the directory page. Then click the **Sales** group to go to the sales group page.
2. On the Sales group page, click **Add Members**. Add the user named **Bob** to the sales group. The user named **Dave** should not be a member of the group.

3. On the Sales group page, click **Properties**, then copy the **Object ID** for the sales group at the bottom of the page.

4. Navigate back to your mobile service configuration page and add the object id as an app setting named **AAD\_SALES\_GROUP\_ID**. This tutorial uses group's object id as an app setting instead of looking up the id based on the group name. This is because the group name may change where the id stays the same.

## Create a custom authorization attribute on the mobile service
In this section you will create a new custom authorization attribute that can be used to perform access checks on mobile service operations. The attribute will look up an Active Directory group based on the role name passed to it. It will then perform access checks based on that group's membership.
1. In Visual Studio, right click mobile service .NET backend project and click **Manage NuGet Packages**.
2. In the NuGet Package Manager dialog, enter **ADAL** in the search criteria to find and install the **Active Directory Authentication Library** for your mobile service. This tutorial was most recently tested with the 3.3.205061641-alpha (Prerelease) version of the ADAL package.
3. In Visual Studio, right click your mobile service project and click **Add** then **New Folder**. Name the new folder **Utilities**.
4. In Visual Studio, right click the new **Utilities** folder and add a new class file named **AuthorizeAadRole.cs**.
![][0]
5. In the AuthorizeAadRole.cs file, add the following `using` statements at the top of the file.
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using Newtonsoft.Json;
using Microsoft.WindowsAzure.Mobile.Service.Security;
using Microsoft.WindowsAzure.Mobile.Service;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Globalization;
using System.IO;
6. In AuthorizeAadRole.cs, add the following enumerated type to the Utilities namespace. In this example we only deal with the **Sales** role. The others are just examples of groups you might use.
public enum AadRoles
{
Sales,
Management,
Development
}
7. In AuthorizeAadRole.cs, add the following `AuthorizeAadRole` class definition to the Utilities namespace.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class AuthorizeAadRole : AuthorizationFilterAttribute
{
private bool isInitialized;
private bool isHosted;
private ApiServices services = null;
// Constants used with ADAL and the Graph REST API for AAD
private const string AadInstance = "https://login.windows.net/{0}";
private const string GraphResourceId = "https://graph.windows.net/";
private const string APIVersion = "?api-version=2013-04-05";
// App settings pulled from the Mobile Service
private string tenantdomain;
private string clientid;
private string clientkey;
private Dictionary groupIds = new Dictionary();
private string token = null;
public AuthorizeAadRole(AadRoles role)
{
this.Role = role;
}
// private class used to serialize the Graph REST API web response
private class MembershipResponse
{
public bool value;
}
public AadRoles Role { get; private set; }
// Generate a local dictionary for the role group ids configured as
// Mobile Service app settings
private void InitGroupIds()
{
}
// Use ADAL and the authentication app settings from the Mobile Service to
// get an AAD access token
private string GetAADToken()
{
}
// Given an AAD user id, check membership against the group associated with the role.
private bool CheckMembership(string memberId)
{
}
// Called when the user is attempting authorization
public override void OnAuthorization(HttpActionContext actionContext)
{
}
}
8. In AuthorizeAadRole.cs, update the `InitGroupIds` method on the `AuthorizeAadRole` class as follows. This method creates a dictionary mapping of the group ids to each role.
private void InitGroupIds()
{
string groupId;
if (services == null)
return;
if (!groupIds.ContainsKey((int)AadRoles.Sales))
{
if (services.Settings.TryGetValue("AAD_SALES_GROUP_ID", out groupId))
{
groupIds.Add((int)AadRoles.Sales, groupId);
}
else
services.Log.Error("AAD_SALES_GROUP_ID app setting not found.");
}
}
9. In AuthorizeAadRole.cs, update the `GetAADToken` method on the `AuthorizeAadRole` class. This method uses the app settings stored in the Mobile Service to get an access token to the AAD from ADAL.
>[AZURE.NOTE] ADAL for .NET includes an in-memory token cache by default to help alleviate extra network traffic against your Active Directory. However, you can write your own cache implementation or disable caching entirely. For more information see [ADAL for .NET].
// Use ADAL and the authentication app settings from the Mobile Service to get an AAD access token
private async Task GetAADToken()
{
// Try to get the required AAD authentication app settings from the mobile service.
if (!(services.Settings.TryGetValue("AAD_CLIENT_ID", out clientid) &
services.Settings.TryGetValue("AAD_CLIENT_KEY", out clientkey) &
services.Settings.TryGetValue("AAD_TENANT_DOMAIN", out tenantdomain)))
{
services.Log.Error("GetAADToken() : Could not retrieve mobile service app settings.");
return null;
}
ClientCredential clientCred = new ClientCredential(clientid, clientkey);
string authority = String.Format(CultureInfo.InvariantCulture, AadInstance, tenantdomain);
AuthenticationContext authContext = new AuthenticationContext(authority);
AuthenticationResult result = await authContext.AcquireTokenAsync(GraphResourceId, clientCred);
if (result != null)
token = result.AccessToken;
else
services.Log.Error("GetAADToken() : Failed to return a token.");
return token;
}
10. In AuthorizeAadRole.cs, update the `CheckMembership` method on the `AuthorizeAadRole` class. This method receives a user's object id. It then uses the AAD Graph REST API to check that object id to see if it is a member id for the group associated to the role selected on the `AuthorizeAadRole` class
private bool CheckMembership(string memberId)
{
bool membership = false;
string url = GraphResourceId + tenantdomain + "/isMemberOf" + APIVersion;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
// Use the Graph REST API to check group membership in the AAD
try
{
request.Method = "POST";
request.ContentType = "application/json";
request.Headers.Add("Authorization", token);
using (var sw = new StreamWriter(request.GetRequestStream()))
{
// Request body must have the group id and a member id to check for membership
string body = String.Format("\"groupId\":\"{0}\",\"memberId\":\"{1}\"",
groupIds[(int)Role], memberId);
sw.Write("{" + body + "}");
}
WebResponse response = request.GetResponse();
StreamReader sr = new StreamReader(response.GetResponseStream());
string json = sr.ReadToEnd();
MembershipResponse membershipResponse = JsonConvert.DeserializeObject(json);
membership = membershipResponse.value;
}
catch (Exception e)
{
services.Log.Error("OnAuthorization() exception : " + e.Message);
}
return membership;
}
11. In AuthorizeAadRole.cs, update the `OnAuthorization` method in the `AuthorizeAadRole` class with the following code. This code expects that the user calling into the Mobiile Service has authenticated with the AAD. It then gets the user's AAD object id and checks membership with the Active Directory group that corresponds to the role.
>[AZURE.NOTE] You could look up the Active Directory group by name. However, in many cases it's a better practice to store the group id as a mobile service app setting. This is because the group name is more likely to change but, the id stays the same.
public override void OnAuthorization(HttpActionContext actionContext)
{
if (actionContext == null)
{
throw new ArgumentNullException("actionContext");
}
services = new ApiServices(actionContext.ControllerContext.Configuration);
// Check whether we are running in a mode where local host access is allowed
// through without authentication.
if (!this.isInitialized)
{
HttpConfiguration config = actionContext.ControllerContext.Configuration;
this.isHosted = config.GetIsHosted();
this.isInitialized = true;
}
// No security when hosted locally
if (!this.isHosted && actionContext.RequestContext.IsLocal)
{
services.Log.Warn("AuthorizeAadRole: Local Hosting.");
return;
}
ApiController controller = actionContext.ControllerContext.Controller as ApiController;
if (controller == null)
{
services.Log.Error("AuthorizeAadRole: No ApiController.");
}
bool isAuthorized = false;
try
{
// Initialize a mapping for the group id to our enumerated type
InitGroupIds();
// Retrieve a AAD token from ADAL
GetAADToken();
if (token == null)
{
services.Log.Error("AuthorizeAadRole: Failed to get an AAD access token.");
}
else
{
// Check group membership to see if the user is part of the group that corresponds to the role
if (!string.IsNullOrEmpty(groupIds[(int)Role]))
{
ServiceUser serviceUser = controller.User as ServiceUser;
if (serviceUser != null && serviceUser.Level == AuthorizationLevel.User)
{
var idents = serviceUser.GetIdentitiesAsync().Result;
AzureActiveDirectoryCredentials clientAadCredentials =
idents.OfType().FirstOrDefault();
if (clientAadCredentials != null)
{
isAuthorized = CheckMembership(clientAadCredentials.ObjectId);
}
}
}
}
}
catch (Exception e)
{
services.Log.Error(e.Message);
}
finally
{
if (isAuthorized == false)
{
services.Log.Error("Denying access");
actionContext.Response = actionContext.Request
.CreateErrorResponse(HttpStatusCode.Forbidden,
"User is not logged in or not a member of the required group");
}
}
}
12. Save your changes to AuthorizeAadRole.cs.
## Add role based access checking to the database operations
1. In Visual Studio, expand the **Controllers** folder under the mobile service project. Open TodoItemController.cs.
2. In TodoItemController.cs, add a `using` statement for your utilities namespace that contains the custom authorization attribute.
using todolistService.Utilities;
3. In TodoItemController.cs, you can add the attribute to your controller class or individual methods depending on how you want access checked. If you want all controller operations to check access based on the same role, just add the attribute to the class. Add the attribute to the class as follows for testing this tutorial.
[AuthorizeAadRole(AadGroups.Sales)]
public class TodoItemController : TableController
If you only wanted to access check insert, update, and delete operations, you would set the attribute only on those methods as follows.
// PATCH tables/TodoItem
[AuthorizeAadRole(AadGroups.Sales)]
public Task PatchTodoItem(string id, Delta patch)
{
return UpdateAsync(id, patch);
}
// POST tables/TodoItem
[AuthorizeAadRole(AadGroups.Sales)]
public async Task PostTodoItem(TodoItem item)
{
TodoItem current = await InsertAsync(item);
return CreatedAtRoute("Tables", new { id = current.Id }, current);
}
// DELETE tables/TodoItem
[AuthorizeAadRole(AadGroups.Sales)]
public Task DeleteTodoItem(string id)
{
return DeleteAsync(id);
}
4. Save TodoItemController.cs and build the mobile service to verify no syntax errors.
5. Publish the mobile service to your Azure account.
## Test the client's access
The instructions and screenshots below apply to testing a Windows Store client but, you can test this on any of the other platforms supported by Azure Mobile Services.
1. In Visual Studio,run the client app and attempt to authenticate with the user account we created named Dave.

2. Dave doesn't have membership to the Sales group. So the role based access check will denied access to the table operations. Close the client app.

3. In Visual Studio, run the client app again. This time authenticate with the user account we created named Bob.

4. Bob does have membership to the Sales group. So the role based access check will allow access to the table operations.

[0]: ./media/mobile-services-dotnet-backend-windows-store-dotnet-aad-rbac/add-authorize-aad-role-class.png
[Add Authentication to your app]: mobile-services-dotnet-backend-windows-universal-dotnet-get-started-users.md
[How to Register with the Azure Active Directory]: mobile-services-how-to-register-active-directory-authentication.md
[Directory Sync Scenarios]: http://msdn.microsoft.com/library/azure/jj573653.aspx
[Store Server Scripts]: mobile-services-store-scripts-source-control.md
[Register to use an Azure Active Directory Login]: mobile-services-how-to-register-active-directory-authentication.md
[Graph REST API]: http://msdn.microsoft.com/library/azure/hh974478.aspx
[IsMemberOf]: http://msdn.microsoft.com/library/azure/dn151601.aspx
[ADAL for .NET]: https://msdn.microsoft.com/library/azure/jj573266.aspx
================================================
FILE: docs/mobile-services-dotnet-backend-windows-store-dotnet-get-started.md
================================================
# Get started with Mobile Services
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal JavaScript | Javascript)](mobile-services-javascript-backend-windows-store-javascript-get-started.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started.md)
- [(Android | Javascript)](mobile-services-android-get-started.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started.md)
- [(HTML | Javascript)](mobile-services-html-get-started.md)
- [(PhoneGap | Javascript)](mobile-services-javascript-backend-phonegap-get-started.md)
- [(Sencha | Javascript)](partner-sencha-mobile-services-get-started.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This tutorial shows you how to add a cloud-based backend service to a universal Windows app using Azure Mobile Services. Universal Windows app solutions include projects for both Windows Store 8.1 and Windows Phone Store 8.1 apps and a common shared project. For more information, see [Build universal Windows apps that target Windows and Windows Phone](http://msdn.microsoft.com/library/windows/apps/xaml/dn609832.aspx).
In this tutorial, you will create both a new mobile service and a simple *To do list* app that stores app data in the new mobile service. The mobile service that you will create uses the supported .NET languages using Visual Studio for server-side business logic and to manage the mobile service. To create a mobile service that lets you write your server-side business logic in JavaScript, see the JavaScript backend version of this topic.
>[AZURE.NOTE]This topic shows you how to create a new mobile service project and universal Windows app by using the Azure classic portal. By using Visual Studio 2013 Update 3, you can also add a new mobile service project to an existing Visual Studio solution. For more information, see [Add Mobile Services to an existing app](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-data.md).
>To add a mobile service to an Windows Phone 8.0 or Windows Phone Silverlight 8.1 app project, see [Add Mobile Services to an existing Windows Phone app](mobile-services-windows-phone-get-started-data.md).
The following are screen captures from the completed app:

Windows Store app

Windows Phone Store app
Completing this tutorial is a prerequisite for all other Mobile Services tutorials for Windows Store and Windows Phone Store apps.
To complete this tutorial, you need the following:
* An active Azure account. If you don't have an account, you can sign up for an Azure trial and get up to 10 free mobile services that you can keep using even after your trial ends. For details, see [Azure Free Trial](https://azure.microsoft.com/pricing/free-trial/?WT.mc_id=A0E0E5C02&returnurl=http%3A%2F%2Fazure.microsoft.com%2Fen-us%2Fdocumentation%2Farticles%2Fmobile-services-dotnet-backend-windows-store-dotnet-get-started%2F).
* [Visual Studio 2013].
## Create a new mobile service
Follow these steps to create a new mobile service.
1. Log into the [Azure classic portal](https://manage.windowsazure.com/). At the bottom of the navigation pane, click **+NEW**. Expand **Compute** and **Mobile Service**, then click **Create**.

This displays the **Create a Mobile Service** dialog.
2. In the **Create a Mobile Service** page, select **Create a free 20 MB SQL Database**, select **.NET** runtime, then type a subdomain name for the new mobile service in the **URL** textbox. Click the right arrow button to go to the next page.

This displays the **Specify database settings** page.
> [AZURE.NOTE] As part of this tutorial, you create a new SQL Database instance and server. You can reuse this new database and administer it as you would any other SQL Database instance. If you already have a database in the same region as the new mobile service, you can instead choose **Use existing Database** and then select that database. The use of a database in a different region is not recommended because of additional bandwidth costs and higher latencies.
3. In **Name**, type the name of the new database, then type **Login name**, which is the administrator login name for the new SQL Database server, type and confirm the password, and click the check button to complete the process.

You have now created a new mobile service that can be used by your mobile apps.
## Create a new universal Windows app
Once you have created your mobile service, you can follow an easy quickstart in the Azure classic portal to either create a new app or modify an existing app to connect to your mobile service.
In this section you will create a new universal Windows app that is connected to your mobile service.
1. In the [Azure classic portal], click **Mobile Services**, and then click the mobile service that you just created.
2. In the quickstart tab, click **Windows** under **Choose platform** and expand **Create a new Windows Store app**.
This displays the three easy steps to create a Windows Store app connected to your mobile service.

3. If you haven't already done so, download and install [Visual Studio 2013] on your local computer or virtual machine.
4. Under **Download and run your app and service locally**, select a language for your Windows Store app, then click **Download**.
This downloads a solution contains projects for both the mobile service and for the sample _To do list_ application that is connected to your mobile service. Save the compressed project file to your local computer, and make a note of where you save it.
## Test the app against the local mobile service
The mobile service project that you download lets you to run your new mobile service right on your local computer or virtual machine. This makes it easy to debug your service code before you even publish it to Azure.
In this section, you will test your new app against the mobile service running locally.
1. Browse to the location where you saved the compressed project files, expand the files on your computer, and open the solution file in Visual Studio.
2. In the Solution Explorer in Visual Studio, right-click your service project, click **Set as StartUp Project**, and then press the **F5** key to build the project and start the mobile service locally.

A web page is displayed after the mobile service starts successfully.
3. To test the store app, right-click your client app project, click **Set as StartUp Project**, and then press the **F5** key to rebuild the project and start the app.
This starts the app, which connects to the local mobile service instance.
4. In the app, type meaningful text, such as _Complete the tutorial_, in **Insert a TodoItem**, and then click **Save**.
This sends a POST request to the local mobile service. Data from the request is inserted into the TodoItem table. Items stored in the table are returned by the mobile service, and the data is displayed in the second column in the app.
>[AZURE.NOTE]You can review the code that accesses your mobile service to query and insert data, which is found in the MainPage.xaml.cs file.
## Publish your mobile service
1. In Visual Studio, right-click the project, click **Publish** > **Microsoft Azure Mobile Services**. Instead of using Visual Studio, [you may also use Git](./
mobile-services-dotnet-backend-store-code-source-control.md).
2. Sign in with Azure credentials and select your service from **Existing Mobile Services**. Visual Studio downloads your publish settings directly from Azure. Finally, click **Publish**.
In the Shared code project, open the App.xaml.cs file, locate the code that creates a MobileServiceClient instance, comment-out the code that creates this client using localhost and uncomment the code that creates the client using the remote mobile service URL, which looks like the following:
public static MobileServiceClient MobileService = new MobileServiceClient(
"https://todolist.azure-mobile.net/",
"XXXX-APPLICATION-KEY-XXXXX");
The client will now access the mobile service published to Azure.
## Test the app against the mobile service hosted in Azure
Now that the mobile service is published and the client is connected to the remote mobile service hosted in Azure, we can run the app using Azure for item storage.
1. Press the F5 key to rebuild the project and start the Windows Store app.
2. In the app, type meaningful text, such as *Complete the tutorial*, in **Insert a TodoItem**, and then click **Save**.

This sends a POST request to the new mobile service hosted in Azure.
3. Stop debugging and change the default start up project in the universal Windows solution to the Windows Phone Store app and press F5 again.

Notice that data saved from the previous step is loaded from the mobile service after the app starts.
## Next Steps
Now that you have completed the quickstart, learn how to perform additional important tasks in Mobile Services:
* [Add Mobile Services to an existing app][Get started with data]
Learn more about storing and querying data using Mobile Services.
* [Get started with offline data sync]
Learn how to use offline data sync to make your app responsive and robust.
* [Add authentication to your Mobile Services app ][Get started with authentication]
Learn how to authenticate users of your app with an identity provider.
* [Add push notifications to your app][Get started with push notifications]
Learn how to send a very basic push notification to your app.
* [Troubleshoot a Mobile Services .NET backend]
Learn how to diagnose and fix issues that can arise with a Mobile Services .NET backend.
For more information about universal Windows apps, see [Supporting multiple device platforms from a single mobile service](mobile-services-how-to-use-multiple-clients-single-service.md#shared-vs).
[Visual Studio 2013]: https://go.microsoft.com/fwLink/p/?LinkID=257546
[Get started with data]: mobile-services-dotnet-backend-windows-universal-dotnet-get-started-data.md
[Get started with offline data sync]: mobile-services-windows-store-dotnet-get-started-offline-data.md
[Get started with authentication]: mobile-services-dotnet-backend-windows-universal-dotnet-get-started-users.md
[Get started with push notifications]: mobile-services-dotnet-backend-windows-universal-dotnet-get-started-push.md
[Visual Studio Professional 2013]: https://go.microsoft.com/fwLink/p/?LinkID=257546
[Mobile Services SDK]: http://go.microsoft.com/fwlink/?LinkId=257545
[JavaScript and HTML]: mobile-services-win8-javascript/
[Azure classic portal]: https://manage.windowsazure.com/
[Troubleshoot a Mobile Services .NET backend]: mobile-services-dotnet-backend-how-to-troubleshoot.md
================================================
FILE: docs/mobile-services-dotnet-backend-windows-store-dotnet-leaderboard.md
================================================
# Creating a Leaderboard App with Azure Mobile Services .NET Backend
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This tutorial shows how build a Windows Store app using Azure Mobile Services with a .NET backend. Azure Mobile Services provides a scalable and secure backend with built-in authentication, monitoring, push notifications, and other features, plus a cross-platform client library for building mobile apps. The .NET backend for Mobile Services is based on [ASP.NET Web API](http://asp.net/web-api), and gives .NET developers a first-class way to create REST APIs.
## Overview
Web API is an open-source framework that gives .NET developers a first-class way to create REST APIs. You can host a Web API solution on Azure Websites, on Azure Mobile Services using the .NET backend, or even self-hosted in a custom process. Mobile Services is a hosting environment that is designed especially for mobile apps. When you host your Web API service on Mobile Services, you get the following advantages in addition to data storage:
- Built-in authentication with social providers and Azure Active Directory (AAD).
- Push notifications to apps using device-specific notification services.
- A full set of client libraries that make it easy to access your service from any app.
- Built-in logging and diagnostics.
In this tutorial you will:
- Create a REST API using Azure Mobile Services.
- Publish the service to Azure.
- Create a Windows Store app that consumes the service.
- Use Entity Framework (EF) to create foreign key relations and data transfer objects (DTOs).
- Use ASP.NET Web API to define a custom API.
This tutorial uses [Visual Studio 2013 latest update](http://go.microsoft.com/fwlink/p/?LinkID=390465).
## About the sample app
A *leaderboard* shows a list of players for a game, along with their scores and the rank of each player. A leaderboard might be part of a larger game, or could be a separate app. A leaderboard is a real-world application, but is simple enough for a tutorial. Here is a screen shot of the app:
![][1]
To keep the app simple, there is no actual game. Instead, you can add players and submit a score for each player. When you submit a score, the mobile service calculates the new rankings. On the back end, the mobile service creates a database with two tables:
- Player. Contains the player ID and name.
- PlayerRank. Contains a player's score and rank.
PlayerRank has a foreign key to Player. Each player has zero or one PlayerRank.
In a real leaderboard app, PlayerRank might also have a game ID, so that a player could submit scores for more than one game.
![][2]
The client app can perform the full set of CRUD operations on Players. It can read or delete existing PlayerRank entities, but it cannot create or update them directly. That's because the rank value is calculated by the service. Instead, the client submits a score, and the service updates the ranks for all players.
Download the completed project [here](http://code.msdn.microsoft.com/Leaderboard-App-with-Azure-9acf63af).
## Create the project
Launch Visual Studio and create a new ASP.NET Web Application project. Name the project Leaderboard.
![][3]
In Visual Studio 2013, the ASP.NET Web Application project includes a template for Azure Mobile Service. Select this template and click **OK**.
![][4]
The project template includes an example controller and data object.
![][5]
These aren't needed for the tutorial, so you can delete them from the project. Also remove the references to TodoItem in WebApiConfig.cs and LeaderboardContext.cs.
## Add data models
You will use [EF Code First](http://msdn.microsoft.com/data/ee712907#codefirst) to define the database tables. Under the DataObjects folder, add a class named `Player`.
using Microsoft.WindowsAzure.Mobile.Service;
namespace Leaderboard.DataObjects
{
public class Player : EntityData
{
public string Name { get; set; }
}
}
Add another class named `PlayerRank`.
using Microsoft.WindowsAzure.Mobile.Service;
using System.ComponentModel.DataAnnotations.Schema;
namespace Leaderboard.DataObjects
{
public class PlayerRank : EntityData
{
public int Score { get; set; }
public int Rank { get; set; }
[ForeignKey("Id")]
public virtual Player Player { get; set; }
}
}
Notice that both classes inherit from the **EntityData** class. Deriving from **EntityData** makes it easy for the app consume the data, using the cross-platform client library for Azure Mobile Services. **EntityData** also makes it easier for an app to [handle database write conflicts](mobile-services-windows-store-dotnet-handle-database-conflicts.md).
The `PlayerRank` class has a [navigation property](http://msdn.microsoft.com/data/jj713564.aspx) that points to the related `Player` entity. The **[ForeignKey]** attribute tells EF that the `Player` property represents a foreign key.
## Add Web API controllers
Next, you will add Web API controllers for `Player` and `PlayerRank`. Instead of plain Web API controllers, you will add a special kind of controller called a *table controller*, designed specifically for Azure Mobile Services.
Right click the Controllers folder > **Add** > **New Scaffolded Item**.
![][6]
In the **Add Scaffold** dialog, expand **Common** on the left and select **Azure Mobile Services**. Then select **Azure Mobile Services Table Controller**. Click **Add**.
![][7]
In the **Add Controller** dialog:
1. Under **Model class**, select Player.
2. Under **Data context class**, select MobileServiceContext.
3. Name the controller "PlayerController".
4. Click **Add**.
This step adds a file named PlayerController.cs to the project.
![][8]
The controller derives from **TableController**. This class inherits **ApiController**, but is specialized for Azure Mobile Services.
- Routing: The default route for a **TableController** is `/tables/{table_name}/{id}`, where *table_name* matches the entity name. So the route for the Player controller is */tables/player/{id}*. This routing convention makes **TableController** consistent with the Mobile Services [REST API](http://msdn.microsoft.com/library/azure/jj710104.aspx).
- Data access: For database operations, the **TableController** class uses the **IDomainManager** interface, which defines an abstraction for data access. The scaffolding uses **EntityDomainManager**, which is a concrete implementation of **IDomainManager** that wraps an EF context.
Now add a second controller for PlayerRank entities. Follow the same steps, but choose PlayerRank for the model class. Use the same data context class; don't create a new one. Name the controller "PlayerRankController".
## Use a DTO to return related entities
Recall that `PlayerRank` has a related `Player` entity:
public class PlayerRank : EntityData
{
public int Score { get; set; }
public int Rank { get; set; }
[ForeignKey("Id")]
public virtual Player Player { get; set; }
}
The Mobile Service client library does not support navigation properties, and they will not be serialized. For example, here is the raw HTTP response for GET `/tables/PlayerRank`:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 97
Content-Type: application/json; charset=utf-8
Expires: 0
Server: Microsoft-IIS/8.0
Date: Mon, 21 Apr 2014 17:58:43 GMT
[{"id":"1","rank":1,"score":150},{"id":"2","rank":3,"score":100},{"id":"3","rank":1,"score":150}]
Notice that `Player` is not included in the object graph. To include the player, we can flatten the object graph by defining a *data transfer object* (DTO).
A DTO is an object that defines how data is sent over the network. DTOs are useful whenever you want the wire format to look different than your database model. To create a DTO for `PlayerRank`, add a new class named `PlayerRankDto` in the DataObjects folder.
namespace Leaderboard.DataObjects
{
public class PlayerRankDto
{
public string Id { get; set; }
public string PlayerName { get; set; }
public int Score { get; set; }
public int Rank { get; set; }
}
}
In the `PlayerRankController` class, we'll use the LINQ **Select** method to convert `PlayerRank` instances to `PlayerRankDto` instances. Update the `GetAllPlayerRank` and `GetPlayerRank` controller methods as follows:
// GET tables/PlayerRank
public IQueryable GetAllPlayerRank()
{
return Query().Select(x => new PlayerRankDto()
{
Id = x.Id,
PlayerName = x.Player.Name,
Score = x.Score,
Rank = x.Rank
});
}
// GET tables/PlayerRank/48D68C86-6EA6-4C25-AA33-223FC9A27959
public SingleResult GetPlayerRank(string id)
{
var result = Lookup(id).Queryable.Select(x => new PlayerRankDto()
{
Id = x.Id,
PlayerName = x.Player.Name,
Score = x.Score,
Rank = x.Rank
});
return SingleResult.Create(result);
}
With these changes, the two GET methods return `PlayerRankDto` objects to the client. The `PlayerRankDto.PlayerName` property is set to the player name. Here is an example response after making this change:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 160
Content-Type: application/json; charset=utf-8
Expires: 0
Server: Microsoft-IIS/8.0
Date: Mon, 21 Apr 2014 19:57:08 GMT
[{"id":"1","playerName":"Alice","score":150,"rank":1},{"id":"2","playerName":"Bob","score":100,"rank":3},{"id":"3","playerName":"Charles","score":150,"rank":1}]
Notice that the JSON payload now includes the player names.
Instead of using LINQ Select statements, another option is to use AutoMapper. This option requires some additional setup code, but enables automatic mapping from domain entities to DTOs. For more information, see [Mapping between Database Types and Client Types in the .NET Backend using AutoMapper](http://blogs.msdn.com/b/azuremobile/archive/2014/05/19/mapping-between-database-types-and-client-type-in-the-net-backend-using-automapper.aspx).
## Define a custom API to submit scores
The `PlayerRank` entity includes a `Rank` property. This value is calculated by the server, and we don't want clients setting it. Instead, clients will use a custom API to submit a player's score. When the server gets a new score, it will update all of the player ranks.
First, add a class named `PlayerScore` to the DataObjects folder.
namespace Leaderboard.DataObjects
{
public class PlayerScore
{
public string PlayerId { get; set; }
public int Score { get; set; }
}
}
In the `PlayerRankController` class, move the `MobileServiceContext` variable from the constructor to a class variable:
public class PlayerRankController : TableController
{
// Add this:
MobileServiceContext context = new MobileServiceContext();
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
// Delete this:
// MobileServiceContext context = new MobileServiceContext();
DomainManager = new EntityDomainManager(context, Request, Services);
}
Delete the following methods from `PlayerRankController`:
- `PatchPlayerRank`
- `PostPlayerRank`
- `DeletePlayerRank`
Then add the following code to `PlayerRankController`:
[Route("api/score")]
public async Task PostPlayerScore(PlayerScore score)
{
// Does this player exist?
var count = context.Players.Where(x => x.Id == score.PlayerId).Count();
if (count < 1)
{
return BadRequest();
}
// Try to find the PlayerRank entity for this player. If not found, create a new one.
PlayerRank rank = await context.PlayerRanks.FindAsync(score.PlayerId);
if (rank == null)
{
rank = new PlayerRank { Id = score.PlayerId };
rank.Score = score.Score;
context.PlayerRanks.Add(rank);
}
else
{
rank.Score = score.Score;
}
await context.SaveChangesAsync();
// Update rankings
// See http://stackoverflow.com/a/575799
const string updateCommand =
"UPDATE r SET Rank = ((SELECT COUNT(*)+1 from {0}.PlayerRanks " +
"where Score > (select score from {0}.PlayerRanks where Id = r.Id)))" +
"FROM {0}.PlayerRanks as r";
string command = String.Format(updateCommand, ServiceSettingsDictionary.GetSchemaName());
await context.Database.ExecuteSqlCommandAsync(command);
return Ok();
}
The `PostPlayerScore` method takes a `PlayerScore` instance as input. (The client will send the `PlayerScore` in an HTTP POST request.) The method does the following:
1. Adds a new `PlayerRank` for the player, if there isn't one in the database already.
2. Updates the player's score.
3. Run a SQL query that batch updates all of the player ranks.
The **[Route]** attribute defines a custom route for this method:
[Route("api/score")]
You could also put the method into a separate controller. There is no particular advantage either way, it just depends how you want to organize your code.
To learn more about the **[Route]** attribute, see [Attribute Routing in Web API](http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2).
## Create the Windows Store app
In this section, I'll describe the Windows Store app that consumes the mobile service. However, I won't focus much on the XAML or the UI. Instead, I want to focus on the application logic. You can download the complete project [here](http://code.msdn.microsoft.com/Leaderboard-App-with-Azure-9acf63af).
Add a new Windows Store App project to the solution. I used the Blank App (Windows) template.
![][10]
Use NuGet Package Manager to add the Mobile Services client library. In Visual Studio, from the **Tools** menu, select **NuGet Package Manager**. Then select **Package Manager Console**. In the Package Manager Console window, type the following command.
Install-Package WindowsAzure.MobileServices -Project LeaderboardApp
The -Project switch specifies which project to install the package to.
## Add model classes
Create a folder named Models and add the following classes:
namespace LeaderboardApp.Models
{
public class Player
{
public string Id { get; set; }
public string Name { get; set; }
}
public class PlayerRank
{
public string Id { get; set; }
public string PlayerName { get; set; }
public int Score { get; set; }
public int Rank { get; set; }
}
public class PlayerScore
{
public string PlayerId { get; set; }
public int Score { get; set; }
}
}
These classes correspond directly to the data entities in the mobile service.
## Create a view model
Model-View-ViewModel (MVVM) is a variant of Model-View-Controller (MVC). The MVVM pattern helps separate application logic from presentation.
- The model represents the domain data (player, player rank, and player score).
- The view model is an abstract representation of the view.
- The view displays the view model and sends user input to the view model. For a Windows Store app, the view is defined in XAML.
![][11]
Add a class named `LeaderboardViewModel`.
using LeaderboardApp.Models;
using Microsoft.WindowsAzure.MobileServices;
using System.ComponentModel;
using System.Net.Http;
using System.Threading.Tasks;
namespace LeaderboardApp.ViewModel
{
class LeaderboardViewModel : INotifyPropertyChanged
{
MobileServiceClient _client;
public LeaderboardViewModel(MobileServiceClient client)
{
_client = client;
}
}
}
Implement **INotifyPropertyChanged** on the view model, so the view model can participate in data binding.
class LeaderboardViewModel : INotifyPropertyChanged
{
MobileServiceClient _client;
public LeaderboardViewModel(MobileServiceClient client)
{
_client = client;
}
// New code:
// INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
}
Next, add observable properties. The XAML will data bind to these properties.
class LeaderboardViewModel : INotifyPropertyChanged
{
// ...
// New code:
// View model properties
private MobileServiceCollection _Players;
public MobileServiceCollection Players
{
get { return _Players; }
set
{
_Players = value;
NotifyPropertyChanged("Players");
}
}
private MobileServiceCollection _Ranks;
public MobileServiceCollection Ranks
{
get { return _Ranks; }
set
{
_Ranks = value;
NotifyPropertyChanged("Ranks");
}
}
private bool _IsPending;
public bool IsPending
{
get { return _IsPending; }
set
{
_IsPending = value;
NotifyPropertyChanged("IsPending");
}
}
private string _ErrorMessage = null;
public string ErrorMessage
{
get { return _ErrorMessage; }
set
{
_ErrorMessage = value;
NotifyPropertyChanged("ErrorMessage");
}
}
}
The `IsPending` property is true while an async operation is pending on the service. The `ErrorMessage` property holds any error message from the service.
Finally, add methods that call through to the service layer.
class LeaderboardViewModel : INotifyPropertyChanged
{
// ...
// New code:
// Service operations
public async Task GetAllPlayersAsync()
{
IsPending = true;
ErrorMessage = null;
try
{
IMobileServiceTable table = _client.GetTable();
Players = await table.OrderBy(x => x.Name).ToCollectionAsync();
}
catch (MobileServiceInvalidOperationException ex)
{
ErrorMessage = ex.Message;
}
catch (HttpRequestException ex2)
{
ErrorMessage = ex2.Message;
}
finally
{
IsPending = false;
}
}
public async Task AddPlayerAsync(Player player)
{
IsPending = true;
ErrorMessage = null;
try
{
IMobileServiceTable table = _client.GetTable();
await table.InsertAsync(player);
Players.Add(player);
}
catch (MobileServiceInvalidOperationException ex)
{
ErrorMessage = ex.Message;
}
catch (HttpRequestException ex2)
{
ErrorMessage = ex2.Message;
}
finally
{
IsPending = false;
}
}
public async Task SubmitScoreAsync(Player player, int score)
{
IsPending = true;
ErrorMessage = null;
var playerScore = new PlayerScore()
{
PlayerId = player.Id,
Score = score
};
try
{
await _client.InvokeApiAsync("score", playerScore);
await GetAllRanksAsync();
}
catch (MobileServiceInvalidOperationException ex)
{
ErrorMessage = ex.Message;
}
catch (HttpRequestException ex2)
{
ErrorMessage = ex2.Message;
}
finally
{
IsPending = false;
}
}
public async Task GetAllRanksAsync()
{
IsPending = true;
ErrorMessage = null;
try
{
IMobileServiceTable table = _client.GetTable();
Ranks = await table.OrderBy(x => x.Rank).ToCollectionAsync();
}
catch (MobileServiceInvalidOperationException ex)
{
ErrorMessage = ex.Message;
}
catch (HttpRequestException ex2)
{
ErrorMessage = ex2.Message;
}
finally
{
IsPending = false;
}
}
}
## Add a MobileServiceClient instance
Open the *App.xaml.cs*file and add a **MobileServiceClient** instance to the `App` class.
// New code:
using Microsoft.WindowsAzure.MobileServices;
namespace LeaderboardApp
{
sealed partial class App : Application
{
// New code.
// TODO: Replace 'port' with the actual port number.
const string serviceUrl = "http://localhost:port/";
public static MobileServiceClient MobileService = new MobileServiceClient(serviceUrl);
// ...
}
}
When you debug locally, the mobile service runs on IIS express. Visual Studio assigns a random port number, so the local URL is http://localhost:*port*, where *port* is the port number. To get the port number, start the service in Visual Studio by pressing F5 to debug. Visual Studio will launch a browser and navigate to the service URL. You can also find the local URL in the project properties, under **Web**.
## Create the main page
In the main page, add an instance of the view model. Then set the view model as the **DataContext** for the page.
public sealed partial class MainPage : Page
{
// New code:
LeaderboardViewModel viewModel = new LeaderboardViewModel(App.MobileService);
public MainPage()
{
this.InitializeComponent();
// New code:
this.DataContext = viewModel;
}
// ...
As I mentioned earlier, I won't show all of the XAML for the app. One benefit of the MVVM pattern is to separate presentation from app logic, so it's easy to change the UI, if you don't like the sample app.
The list of players is displayed in a **ListBox**:
Rankings are displayed in a **ListView**:
All data binding happens through the view model.
## Publish your mobile service
In this step, you will publish your mobile service to Microsoft Azure and modify the app to use the live service.
In Solution Explorer, right-click the Leaderboard project and select **Publish**.
![][12]
In the **Publish** dialog, click **Azure Mobile Services**.
![][13]
If you are not signed into your Azure account already, click **Sign In**.
![][14]
Select an existing Mobile Service, or click **New** to create a new one. Then click **OK** to publish.
![][15]
The publishing process automatically creates the database. You don't need to configure a connection string.
Now you are ready to connect the leaderboard app to the live service. You need two things:
- The URL of the service
- The application key
You can get both from the Azure classic portal. In the portal, click **Mobile Services**, and then click the mobile service. The service URL is listed on the dashboard tab. To get the application key, click **Manage Keys**.
![][16]
In the **Manage Access Keys** dialog, copy the value for the application key.
![][17]
Pass the service URL and the application key to the **MobileServiceClient** constructor.
sealed partial class App : Application
{
// TODO: Replace these strings with the real URL and key.
const string serviceUrl = "https://yourapp.azure-mobile.net/";
const string appKey = "YOUR ACCESSS KEY";
public static MobileServiceClient MobileService = new MobileServiceClient(serviceUrl, appKey);
// ...
Now when you run the app, it communicates with the real service.
## Next Steps
* [Learn more about Azure Mobile Services]
* [Learn more about Web API]
* [Handle database write conflicts]
* [Add push notifications]; for example, when someone adds a new player or updates a score.
* [Get started with authentication]
[Overview]: #overview
[About the sample app]: #about-the-sample-app
[Create the project]: #create-the-project
[Add data models]: #add-data-models
[Add Web API controllers]: #add-web-api-controllers
[Use a DTO to return related entities]: #use-a-dto-to-return-related-entities
[Define a custom API to submit scores]: #define-a-custom-api-to-submit-scores
[Create the Windows Store app]: #create-the-windows-store-app
[Add model classes]: #add-model-classes
[Create a view model]: #create-a-view-model
[Add a MobileServiceClient instance]: #add-a-mobileserviceclient-instance
[Create the main page]: #create-the-main-page
[Publish your mobile service]: #publish-your-mobile-service
[Next Steps]: #next-steps
[1]: ./media/mobile-services-dotnet-backend-windows-store-dotnet-leaderboard/01leaderboard.png
[2]: ./media/mobile-services-dotnet-backend-windows-store-dotnet-leaderboard/02leaderboard.png
[3]: ./media/mobile-services-dotnet-backend-windows-store-dotnet-leaderboard/03leaderboard.png
[4]: ./media/mobile-services-dotnet-backend-windows-store-dotnet-leaderboard/04leaderboard.png
[5]: ./media/mobile-services-dotnet-backend-windows-store-dotnet-leaderboard/05leaderboard.png
[6]: ./media/mobile-services-dotnet-backend-windows-store-dotnet-leaderboard/06leaderboard.png
[7]: ./media/mobile-services-dotnet-backend-windows-store-dotnet-leaderboard/07leaderboard.png
[8]: ./media/mobile-services-dotnet-backend-windows-store-dotnet-leaderboard/08leaderboard.png
[9]: ./media/mobile-services-dotnet-backend-windows-store-dotnet-leaderboard/09leaderboard.png
[10]: ./media/mobile-services-dotnet-backend-windows-store-dotnet-leaderboard/10leaderboard.png
[11]: ./media/mobile-services-dotnet-backend-windows-store-dotnet-leaderboard/11leaderboard.png
[12]: ./media/mobile-services-dotnet-backend-windows-store-dotnet-leaderboard/12leaderboard.png
[13]: ./media/mobile-services-dotnet-backend-windows-store-dotnet-leaderboard/13leaderboard.png
[14]: ./media/mobile-services-dotnet-backend-windows-store-dotnet-leaderboard/14leaderboard.png
[15]: ./media/mobile-services-dotnet-backend-windows-store-dotnet-leaderboard/15leaderboard.png
[16]: ./media/mobile-services-dotnet-backend-windows-store-dotnet-leaderboard/16leaderboard.png
[17]: ./media/mobile-services-dotnet-backend-windows-store-dotnet-leaderboard/17leaderboard.png
[Learn more about Azure Mobile Services]: https://azure.microsoft.com/develop/mobile/resources/
[Learn more about Web API]: http://asp.net/web-api
[Handle database write conflicts]: mobile-services-windows-store-dotnet-handle-database-conflicts.md
[Add push notifications]: https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-windows-store-dotnet-get-started-wns-push-notification/
[Get started with authentication]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-users-dotnet
================================================
FILE: docs/mobile-services-dotnet-backend-windows-store-dotnet-push-notifications-app-users.md
================================================
# Send push notifications to authenticated users
> [AZURE.SELECTOR-LIST (Platform | Backend)]
- [(iOS | JavaScript)](mobile-services-javascript-backend-ios-push-notifications-app-users.md)
- [(Windows 8.x Store C# | .NET)](mobile-services-dotnet-backend-windows-store-dotnet-push-notifications-app-users.md)
- [(Windows 8.x Store C# | JavaScript)](mobile-services-javascript-backend-windows-store-dotnet-push-notifications-app-users.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
## Overview
This topic shows you how to send push notifications to an authenticate user on any registered device. Unlike the previous [push notification][Get started with push notifications] tutorial, this tutorial changes your mobile service to require that a user be authenticated before the client can register with the notification hub for push notifications. Registration is also modified to add a tag based on the assigned user ID. Finally, the server code is updated to send the notification only to the authenticated user instead of to all registrations.
This tutorial supports both Windows Store and Windows Phone Store apps.
## Prerequisites
Before you start this tutorial, you must have already completed these Mobile Services tutorials:
+ [Get started with authentication]
Adds a login requirement to the TodoList sample app.
+ [Get started with push notifications]
Configures the TodoList sample app for push notifications by using Notification Hubs.
After you have completed both tutorials, you can prevent unauthenticated users from registering for push notifications from your mobile service.
## Update the service to require authentication to register
1. In Solution Explorer in Visual Studio, expand the App_Start folder and open the WebApiConfig.cs project file.
2. Add the following line of code to the Register method after the **ConfigOptions** definition:
options.PushAuthorization =
Microsoft.WindowsAzure.Mobile.Service.Security.AuthorizationLevel.User;
This enforces user authentication before registering for push notifications.
2. Right-click the project, click **Add** then click **Class...**.
3. Name the new empty class `PushRegistrationHandler` then click **Add**.
4. At the top of the code page, add the following **using** statements:
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Controllers;
using Microsoft.WindowsAzure.Mobile.Service;
using Microsoft.WindowsAzure.Mobile.Service.Notifications;
using Microsoft.WindowsAzure.Mobile.Service.Security;
5. Replace the existing **PushRegistrationHandler** class with the following code:
public class PushRegistrationHandler : INotificationHandler
{
public Task Register(ApiServices services, HttpRequestContext context,
NotificationRegistration registration)
{
try
{
// Perform a check here for user ID tags, which are not allowed.
if(!ValidateTags(registration))
{
throw new InvalidOperationException(
"You cannot supply a tag that is a user ID.");
}
// Get the logged-in user.
var currentUser = context.Principal as ServiceUser;
// Add a new tag that is the user ID.
registration.Tags.Add(currentUser.Id);
services.Log.Info("Registered tag for userId: " + currentUser.Id);
}
catch(Exception ex)
{
services.Log.Error(ex.ToString());
}
return Task.FromResult(true);
}
private bool ValidateTags(NotificationRegistration registration)
{
// Create a regex to search for disallowed tags.
System.Text.RegularExpressions.Regex searchTerm =
new System.Text.RegularExpressions.Regex(@"facebook:|google:|twitter:|microsoftaccount:",
System.Text.RegularExpressions.RegexOptions.IgnoreCase);
foreach (string tag in registration.Tags)
{
if (searchTerm.IsMatch(tag))
{
return false;
}
}
return true;
}
public Task Unregister(ApiServices services, HttpRequestContext context,
string deviceId)
{
// This is where you can hook into registration deletion.
return Task.FromResult(true);
}
}
The **Register** method is called during registration. This lets you add a tag to the registration that is the ID of the logged-in user. The supplied tags are validated to prevent a user from registering for another user's ID. When a notification is sent to this user, it is received on this and any other device registered by the user.
6. Expand the Controllers folder, open the TodoItemController.cs project file, locate the **PostTodoItem** method and replace the line of code that calls **SendAsync** with the following code:
// Get the logged-in user.
var currentUser = this.User as ServiceUser;
// Use a tag to only send the notification to the logged-in user.
var result = await Services.Push.SendAsync(message, currentUser.Id);
7. Republish the mobile service project.
Now, the service uses the user ID tag to send a push notification (with the text of the inserted item) to all registrations created by the logged-in user.
## Update the app to log in before registration
Next, you need to change the way that push notifications are registered to make sure that the user is authenticated before registration is attempted. The client app updates depend on the way in which you implemented push notifications.
### Using the Add Push Notification Wizard in Visual Studio 2013 Update 2 or a later version
In this method, the wizard generated a new push.register.cs file in your project.
1. In Visual Studio in Solution Explorer, open the app.xaml.cs project file and in the **OnLaunched** event handler comment-out or delete the call to the **UploadChannel** method.
2. Open the push.register.cs project file and replace the **UploadChannel** method, with the following code:
public async static void UploadChannel()
{
var channel =
await Windows.Networking.PushNotifications.PushNotificationChannelManager
.CreatePushNotificationChannelForApplicationAsync();
try
{
// Create a native push notification registration.
await App.MobileService.GetPush().RegisterNativeAsync(channel.Uri);
}
catch (Exception exception)
{
HandleRegisterException(exception);
}
}
This makes sure that registration is done using the same client instance that has the authenticated user credentials. Otherwise, registration will fail with an Unauthorized (401) error.
3. Open the shared MainPage.cs project file, and replace the **ButtonLogin_Click** handler with the following:
private async void ButtonLogin_Click(object sender, RoutedEventArgs e)
{
// Login the user and then load data from the mobile service.
await AuthenticateAsync();
todolistPush.UploadChannel();
// Hide the login button and load items from the mobile service.
this.ButtonLogin.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
await RefreshTodoItems();
}
This makes sure that authentication occurs before push registration is attempted.
4. In the previous code, replace the generated push class name (`todolistPush`) with the name of class generated by the wizard, usually in the format mobile_servicePush.
### Manually enabled push notifications
In this method, you added registration code from the tutorial directly to the app.xaml.cs project file.
1. In Visual Studio in Solution Explorer, open the app.xaml.cs project file and in the **OnLaunched** event handler comment-out or delete the call to **InitNotificationsAsync**.
2. Change the accessibility of the **InitNotificationsAsync** method from `private` to `public` and add the `static` modifier.
3. Open the shared MainPage.cs project file, and replace the **ButtonLogin_Click** handler with the following:
private async void ButtonLogin_Click(object sender, RoutedEventArgs e)
{
// Login the user and then load data from the mobile service.
await AuthenticateAsync();
App.InitNotificationsAsync();
// Hide the login button and load items from the mobile service.
this.ButtonLogin.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
await RefreshTodoItems();
}
This makes sure that authentication occurs before push registration is attempted.
## Test the app
1. In Visual Studio, press the F5 key to run the app.
2. Log in using the selected identity provider and verify that authentication succeeds.
3. In the app, type text in **Insert a TodoItem**, and then click **Save**.
Note that after the insert completes, the app receives a push notification from WNS.
4. (Optional) Repeat steps 1-3 on a different client device and using a different account when logging in.
Verify that the notification is received only on this device, since the previous device was not tagged with the current user ID.
[Updating the service to require authentication for registration]: #register
[Updating the app to log in before registration]: #update-app
[Testing the app]: #test
[Next Steps]:#next-steps
[Get started with authentication]: mobile-services-dotnet-backend-windows-store-dotnet-get-started-users.md
[Get started with push notifications]: mobile-services-dotnet-backend-windows-universal-dotnet-get-started-push.md
================================================
FILE: docs/mobile-services-dotnet-backend-windows-universal-dotnet-get-started-data.md
================================================
# Add Mobile Services to an existing app
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-data.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-windows-phone-get-started-data.md)
- [(Android | Javascript)](mobile-services-android-get-started-data.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
## Overview
This topic shows you how to use Azure Mobile Services as a backend data source for a Windows Store app. In this tutorial, you will download a Visual Studio 2013 project for an app that stores data in memory, create a new mobile service, integrate the mobile service with the app, and view the changes to data made when running the app.
The mobile service that you will create in this tutorial is a .NET backend mobile service. .NET backend enables you to use .NET languages and Visual Studio for server-side business logic in the mobile service, and you can run and debug your mobile service on your local computer. To create a mobile service that lets you write your server-side business logic in JavaScript, see the JavaScript backend version of this topic.
>[AZURE.NOTE]This topic shows you how to use the tooling in Visual Studio Professional 2013 with Update 3 to connect a new mobile service to a universal Windows app. The same steps can be used to connect a mobile service to a Windows Store or Windows Phone Store 8.1 app. To connect a mobile service to a Windows Phone 8.0 or Windows Phone Silverlight 8.1 app, see [Get started with data for Windows Phone](mobile-services-windows-phone-get-started-data.md).
## Prerequisites
To complete this tutorial, you need the following:
* An active Azure account. If you don't have an account, you can create a free trial account in just a couple of minutes. For details, see [Azure Free Trial](https://azure.microsoft.com/pricing/free-trial/?WT.mc_id=A0E0E5C02&returnurl=http%3A%2F%2Fazure.microsoft.com%2Fdocumentation%2Farticles%2Fmobile-services-dotnet-backend-windows-universal-dotnet-get-started-data%2F).
* Visual Studio 2013 (Update 3 or a later version).
## Download the GetStartedWithData project
This tutorial is built on the [GetStartedWithMobileServices app](http://go.microsoft.com/fwlink/p/?LinkID=510826), which is a universal Windows app project in Visual Studio 2013. The UI for this app is identical to the app generated by the Mobile Services quickstart, except that added items are stored locally in memory.
1. Download the C# version of the GetStartedWithMobileServices sample app from the [Developer Code Samples site].
2. In Visual Studio 2013, open the downloaded project and examine the MainPage.xaml.cs file found in the GetStartedWithData.Shared project folder.
Notice that added **TodoItem** objects are stored in an in-memory **ObservableCollection<TodoItem>**.
3. Press the **F5** key to rebuild the project and start the app.
4. In the app, type some text in **Insert a TodoItem**, then click **Save**.

Notice that the saved text is displayed.
5. Right-click the Windows Phone 8.1 project, click **Set as Start-up Project**, then press **F5** to start the Windows Phone Store app.

6. Repeat steps 3 and 4 to verify that the sample behaves the same way.
## Create a new mobile service from Visual Studio
The following steps create a new mobile service in Azure and add code to your project that connects your app to this new service. Visual Studio 2013 connects to Azure on your behalf to create the new mobile service by using the credentials that you provide. When you create a new mobile service, you must specify an Azure SQL Database that is used by the mobile service to store app data.
1. In Visual Studio 2013, open Solution Explorer, right-click the Windows Store app project, click **Add**, and then click **Connected Service...**.
2. In the Services Manager dialog, click **Create service...**, then select **<Manage...>** from **Subscription** in the Create Mobile Service dialog.

3. In Manage Microsoft Azure Subscriptions, click **Sign In...** to sign in to your Azure account (if required), select an available subscription, then click **Close**.
When your subscription already has one or more existing mobile services, the service names are displayed.
5. Back in the **Create Mobile Service** dialog, select your **Subscription**, the **.NET Framework** backend in **Runtime** and a **Region** for your mobile service, then type a **Name** for your mobile service.
>[AZURE.NOTE]Mobile service names must be unique. A red X is displayed next to **Name** when the name you supplied is not available.
6. In **Database**, select **<Create a free SQL Database>**, supply the **Server user name**, **Server password**, and **Server password confirmation** then click **Create**.

> [AZURE.NOTE]
> As part of this tutorial, you create a new free SQL Database instance and server. You can reuse this new database and administer it as you would any other SQL Database instance. You can only have one free database instance. If you already have a database in the same region as the new mobile service, you can instead choose the existing database. When you choose an existing database, make sure that you supply correct login credentials. If you supply incorrect login credentials, the mobile service is created in an unhealthy state.
7. After the mobile service is created, select the newly created mobile service from the list in Service Manager and click **OK**.
After the wizard completes, the mobile service project is added to your solution, the required NuGet packages are installed, a reference to the Mobile Services client library is added to the project, and your project source code is updated.
7. In Solution Explorer, open the App.xaml.cs code file in the GetStartedWithData.Shared project folder, and notice the new static field that was added to the **App** class inside a Windows Store app conditional compilation block, which looks like the following example:
public static Microsoft.WindowsAzure.MobileServices.MobileServiceClient
todolistClient = new Microsoft.WindowsAzure.MobileServices.MobileServiceClient(
"https://todolist.azure-mobile.net/",
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
This code provides access to your new mobile service in your app by using an instance of the [MobileServiceClient](http://go.microsoft.com/fwlink/p/?LinkId=302030) class. The client is created by supplying the URI and the application key of the new mobile service. This static field is available to all pages in your app.
8. Right-click the Windows Phone app project, click **Add**, click **Connected Service...**, select the mobile service that you just created, and then click **OK**. The same code is added to the shared App.xaml.cs file, but this time within a Windows Phone app conditional compilation block.
At this point, both the Windows Store and Windows Phone Store apps are connected to the new mobile service. The next step is to test the new mobile service project.
## Test the mobile service project locally
1. In Visual Studio in Solution Explorer, right click the service project and click **Start new instance** under the **Debug** context menu.

Visual Studio opens the default web page for your service. By default, Visual Studio hosts your mobile service locally in IIS Express.
2. Right-click the tray icon for IIS Express on the Windows taskbar and verify that your mobile service has started.

3. On the start page of your .NET backend, click **try it out**.

This displays the API documentation page, which you can use to test the mobile service.
>[AZURE.NOTE]Authentication is not required to access this page when running locally. When running in Azure, you must supply the application key as the password (with no username) to access this page.
4. Click the **GET tables/TodoItem** link.

This displays the GET response page for the API.
5. Click **try this out** and then click **send**.

This sends a GET request to the local mobile service to return all rows in the TodoItem table. Because the table is seeded by the initializer, two TodoItem objects are returned in the body of the response message. For more information about initializers, see [How to make data model changes to a .NET backend mobile service](mobile-services-dotnet-backend-how-to-use-code-first-migrations.md).

## Update the app to use the mobile service
In this section you will update the universal Windows app to use the mobile service as a backend service for the application. You only need to make changes to the MainPage.cs project file in the GetStartedWithData.Shared project folder.
2. Replace the TodoItem class definition with the following code:
public class TodoItem
{
public string Id { get; set; }
[Newtonsoft.Json.JsonProperty(PropertyName = "text")]
public string Text { get; set; }
[Newtonsoft.Json.JsonProperty(PropertyName = "complete")]
public bool Complete { get; set; }
}
The **JsonPropertyAttribute** is used to define the mapping between property names in the client type to column names in the underlying data table.
>[AZURE.NOTE] In a universal Windows app project, the TodoItem class is defined in the seperate code file in the shared DataModel folder.
1. In the file MainPage.cs, add or uncomment the following using statements:
using Microsoft.WindowsAzure.MobileServices;
4. Comment-out or delete the line that defines the existing items collection, then uncomment or add the following lines, replacing _<yourClient>_ with the `MobileServiceClient` field added to the App.xaml.cs file when you connected your project to the mobile service:
private MobileServiceCollection items;
private IMobileServiceTable todoTable =
App..GetTable();
This code creates a mobile services-aware binding collection (items) and a proxy class for the database table (todoTable).
4. In the **InsertTodoItem** method, remove the line of code that sets the **TodoItem.Id** property, add the **async** modifier to the method, and uncomment the following line of code:
await todoTable.InsertAsync(todoItem);
This code inserts a new item into the table.
5. Replace the **RefreshTodoItems** method with the following code:
private async void RefreshTodoItems()
{
MobileServiceInvalidOperationException exception = null;
try
{
// Query that returns all items.
items = await todoTable.ToCollectionAsync();
}
catch (MobileServiceInvalidOperationException e)
{
exception = e;
}
if (exception != null)
{
await new MessageDialog(exception.Message, "Error loading items").ShowAsync();
}
else
{
ListItems.ItemsSource = items;
this.ButtonSave.IsEnabled = true;
}
}
This sets the binding to the collection of items in `todoTable`, which contains all of the **TodoItem** objects returned from the mobile service. If there is a problem executing the query, a message box is raised to display the errors.
6. In the **UpdateCheckedTodoItem** method, add the **async** modifier to the method, and uncomment the following line of code:
await todoTable.UpdateAsync(item);
This sends an item update to the mobile service.
Now that the app has been updated to use Mobile Services for backend storage, it's time to test the app against Mobile Services.
## Publish the mobile service to Azure
1. In Visual Studio, right-click the project, click **Publish** > **Microsoft Azure Mobile Services**. Instead of using Visual Studio, [you may also use Git](./
mobile-services-dotnet-backend-store-code-source-control.md).
2. Sign in with Azure credentials and select your service from **Existing Mobile Services**. Visual Studio downloads your publish settings directly from Azure. Finally, click **Publish**.
## Test the mobile service hosted in Azure
Now we can test both versions of the universal Windows app against the mobile service hosted in Azure.
1. Press the F5 key to rebuild the project and start the Windows Store app.
2. In the app, type meaningful text, such as *Complete the tutorial*, in **Insert a TodoItem**, and then click **Save**.

This sends a POST request to the new mobile service hosted in Azure.
3. Stop debugging and change the default start up project in the universal Windows solution to the Windows Phone Store app and press F5 again.

Notice that data saved from the previous step is loaded from the mobile service after the app starts.
## View the data stored in the SQL Database
The final optional step of this tutorial is to check in the SQL Database associated with the mobile service an review the stored data.
1. In the [Azure classic portal](https://manage.windowsazure.com/), click manage for the database associated with your mobile service.

2. In the portal execute a query to view the changes made by the Windows Store app. Your query will be similar to the following query but use your database name instead of todolist.
SELECT * FROM [todolist].[todoitems]

Note that the table includes Id, __createdAt, __updatedAt, and __version columns. These columns support offline data sync and are implemented in the [EntityData](http://msdn.microsoft.com/library/microsoft.windowsazure.mobile.service.entitydata.aspx) base class. For more information, see [Get started with offline data sync].
This concludes the tutorial.
## Next steps
This tutorial demonstrated the basics of enabling a universal Windows app project to work with data in Mobile Services. Next, consider reading up on one of these other topics:
* [Get started with authentication]
Learn how to authenticate users of your app.
* [Get started with push notifications]
Learn how to send a very basic push notification to your app.
* [Mobile Services C# How-to Conceptual Reference](mobile-services-dotnet-how-to-use-client-library.md)
Learn more about how to use Mobile Services with .NET.
[Validate and modify data with scripts]: https://azure.microsoft.com/develop/mobile/tutorials/validate-modify-and-augment-data-dotnet
[Refine queries with paging]: https://azure.microsoft.com/develop/mobile/tutorials/add-paging-to-data-dotnet
[Get started with Mobile Services]: mobile-services-dotnet-backend-windows-store-dotnet-get-started.md
[Get started with authentication]: mobile-services-dotnet-backend-windows-store-dotnet-get-started-users.md
[Get started with push notifications]: mobile-services-dotnet-backend-windows-store-dotnet-get-started-push.md
[Get started with offline data sync]: mobile-services-windows-store-dotnet-get-started-offline-data.md
[Mobile Services SDK]: http://go.microsoft.com/fwlink/p/?LinkId=257545
[Developer Code Samples site]: http://go.microsoft.com/fwlink/p/?LinkID=510826
[Mobile Services .NET How-to Conceptual Reference]: mobile-services-windows-dotnet-how-to-use-client-library.md
[MobileServiceClient class]: http://go.microsoft.com/fwlink/p/?LinkId=302030
================================================
FILE: docs/mobile-services-dotnet-backend-windows-universal-dotnet-get-started-push.md
================================================
# Add push notifications to your Mobile Services app
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-push.md)
- [(iOS | JavaScript)](mobile-services-javascript-backend-ios-get-started-push.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-push.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-get-started-push.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-javascript-backend-windows-phone-get-started-push.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started-push.md)
- [(Android | Javascript)](mobile-services-javascript-backend-android-get-started-push.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-push.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-push.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-push.md)
- [(Xamarin.Forms | JavaScript)](partner-xamarin-mobile-services-xamarin-forms-get-started-push.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
## Overview
This topic shows you how to use Azure Mobile Services with a .NET backend to send push notifications to a universal Windows app. In this tutorial you enable push notifications using Azure Notification Hubs in a universal Windows app project. When complete, your mobile service will send a push notification from the .NET backend to all registered Windows Store and Windows Phone Store apps each time a record is inserted in the TodoList table. The notification hub that you create is free with your mobile service, can be managed independent of the mobile service, and can be used by other applications and services.
To complete this tutorial, you need the following:
* An active [Microsoft Store account](http://go.microsoft.com/fwlink/p/?LinkId=280045).
* [Visual Studio Community 2013](https://go.microsoft.com/fwLink/p/?LinkID=391934).
## Register your app for push notifications
The following steps registers your app with the Windows Store, configure your mobile service to enable push notifications, and add code to your app to register a device channel with your notification hub. Visual Studio 2013 connects to Azure and to the Windows Store by using the credentials that you provide.
1. In Visual Studio 2013, open Solution Explorer, right-click the Windows Store app project, click **Add** then **Push Notification...**.

This starts the Add Push Notification Wizard.
2. Click **Next**, sign in to your Windows Store account, then supply a name in **Reserve a new name** and click **Reserve**.
This creates a new app registration.
3. Click the new registration in the **App Name** list, then click **Next**.
4. In the **Select a service** page, click the name of your mobile service, then click **Next** and **Finish**.
The notification hub used by your mobile service is updated with the Windows Notification Services (WNS) registration. You can now use Azure Notification Hubs to send notifications from Mobile Services to your app by using WNS.
>[AZURE.NOTE]This tutorial demonstrates sending notifications from a mobile service backend. You can use the same notification hub registration to send notifications from any backend service. For more information, see [Notification Hubs Overview](http://msdn.microsoft.com/library/azure/jj927170.aspx).
5. When you complete the wizard, a new **Push setup is almost complete** page is opened in Visual Studio. This page details an alternate method to configure your mobile service project to send notifications that is different from this tutorial.
The code that is added to your universal Windows app solution by the Add Push Notification wizard is platform-specific. Later in this section, you will remove this redundancy by sharing the Mobile Services client code, which makes the universal app easier to maintain.
[Get started with Mobile Services]: https://azure.microsoft.com/develop/mobile/tutorials/get-started/
[Get started with data]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-data-dotnet/
6. Browse to the `\Services\MobileServices\your_service_name` project folder, open the generated push.register.cs code file, and inspect the **UploadChannel** method that registers the device's channel URL with the notification hub.
7. Open the shared App.xaml.cs code file and notice that a call to the new **UploadChannel** method was added in the **OnLaunched** event handler. This makes sure that registration of the device is attempted whenever the app is launched.
8. Repeat the previous steps to add push notifications to the Windows Phone Store app project, then in the shared App.xaml.cs file, remove the extra call to **UploadChannel** and the remaining `#if...#endif` conditional wrapper. Both projects can now share a single call to **UploadChannel**.
> [AZURE.NOTE] You can also simplify the generated code by unifying the `#if...#endif` wrapped [MobileServiceClient](http://msdn.microsoft.com/library/azure/microsoft.windowsazure.mobileservices.mobileserviceclient.aspx) definitions into a single unwrapped definition used by both versions of the app.
Now that push notifications are enabled in the app, you must update the mobile service to send push notifications.
## Update the service to send push notifications
The following steps update the existing TodoItemController class to send a push notification to all registered devices when a new item is inserted. You can implement similar code in any custom [ApiController](https://msdn.microsoft.com/library/system.web.http.apicontroller.aspx), [TableController](https://msdn.microsoft.com/library/azure/microsoft.windowsazure.mobile.service.tables.tablecontroller.aspx), or anywhere else in your backend services.
1. In Visual Studio Solution Explorer, expand the **Controllers** folder in the mobile service project. Open TodoItemController.cs and update the `PostTodoItem` method definition with the following code:
public async Task PostTodoItem(TodoItem item)
{
TodoItem current = await InsertAsync(item);
// Create a WNS native toast.
WindowsPushMessage message = new WindowsPushMessage();
// Define the XML paylod for a WNS native toast notification
// that contains the text of the inserted item.
message.XmlPayload = @"" +
@"" +
@"" + item.Text + @"" +
@"";
try
{
var result = await Services.Push.SendAsync(message);
Services.Log.Info(result.State.ToString());
}
catch (System.Exception ex)
{
Services.Log.Error(ex.Message, null, "Push.SendAsync Error");
}
return CreatedAtRoute("Tables", new { id = current.Id }, current);
}
This code sends a push notification (with the text of the inserted item) after inserting a todo item. In the event of an error, the code will add an error log entry which is viewable on the **Logs** tab of the mobile service in the [Azure classic portal](https://manage.windowsazure.com/).
>[AZURE.NOTE] You can use template notifications to send a single push notification to clients on multiple platforms. For more information, see [Supporting multiple device platforms from a single mobile service](mobile-services-how-to-use-multiple-clients-single-service.md#push).
2. Republish the mobile service project to Azure.
## Enable push notifications for local testing
You can optionally test push notifications with your mobile service running on the local computer or VM before you publish to Azure. To do this, you must set information about the notification hub used by your app in the web.config file. This information is only used when running locally to connect to the notification hub; it is ignored when published to Azure.
1. Open the readme.html file in the mobile service project folder.
This displays the **Push setup is almost complete** page, if you don't still have it open. The section **Step 3: Modify Web Config** contains the notification hub connection information.
2. In your mobile service project in Visual Studio, open the Web.config file for the service, then in **connectionStrings**, add the **MS_NotificationHubConnectionString** connection string from the **Push setup is almost complete** page.
3. In **appSettings**, replace the value of the **MS_NotificationHubName** app setting with the name of the notification hub found in the **Push setup is almost complete** page.
4. Right-click the mobile service project and click **Debug** then **Start new instance** and make a note of the service root URL of the start up page displayed in the browser.
This is the URL of the local host for the .NET backend project. You will use this URL to test the app against the mobile service running on the local computer.
Now, the mobile service project is configured to connect to the notification hub in Azure when running locally. Note that it is important to use the same notification hub name and connection string as the portal because these project settings in the Web.config file are overridden by the portal settings when running in Azure.
The remaining steps in this section are optional. They allow you to test your app against your mobile service running on a local computer. If you plan to test push notifications using the mobile service running in Azure, you can just skip to the last section. This is because the Add Push Notification wizard already configured your app to connect to your service running in Azure.
>[AZURE.NOTE]Never use a production mobile service for testing and development work. Always publish your mobile service project to a separate staging service for testing.
5. Open the shared App.xaml.cs project file and locate any the lines of code that create a new instance of the [MobileServiceClient] class to access the mobile service running in Azure.
6. Comment-out this code and add code that creates a new [MobileServiceClient] of the same name but using the URL of the local host in the constructor, similar to the following:
// This MobileServiceClient has been configured to communicate with your local
// test project for debugging purposes.
public static MobileServiceClient todolistClient = new MobileServiceClient(
"http://localhost:4584"
);
Using this [MobileServiceClient], the app will connect to the local service instead of the version hosted in Azure. When you want to switch back and run app against the mobile service hosted in Azure, change back to the original [MobileServiceClient] definitions.
## Test push notifications in your app
1. Right-click the Windows Store project, click **Set as StartUp Project**, then press the F5 key to run the Windows Store app.
After the app starts, the device is registered for push notifications.
2. Stop the Windows Store app and repeat the previous step to run the Windows Phone Store app.
At this point, both devices are registered to receive push notifications.
3. Run the Windows Store app again, and type text in **Insert a TodoItem**, and then click **Save**.

Note that after the insert completes, both the Windows Store and the Windows Phone apps receive a push notification from WNS.

The notification is displayed on Windows Phone even when the app isn't running.

## Next steps
This tutorial demonstrated the basics of enabling a Windows Store app to use Mobile Services and Notification Hubs to send push notifications. Next, consider completing the next tutorial, [Send push notifications to authenticated users], which shows how to use tags to send push notifications from a Mobile Service to only an authenticated user.
Learn more about Mobile Services and Notification Hubs in the following topics:
* [Add Mobile Services to an existing app][Get started with data]
Learn more about storing and querying data using mobile services.
* [Add authentication to your app][Get started with authentication]
Learn how to authenticate users of your app with different account types using mobile services.
* [What are Notification Hubs?]
Learn more about how Notification Hubs works to deliver notifications to your apps across all major client platforms.
* [Debug Notification Hubs applications](http://go.microsoft.com/fwlink/p/?linkid=386630)
Get guidance troubleshooting and debugging Notification Hubs solutions.
* [How to use a .NET client for Azure Mobile Services]
Learn more about how to use Mobile Services from C# Windows apps.
[Submit an app page]: http://go.microsoft.com/fwlink/p/?LinkID=266582
[My Applications]: http://go.microsoft.com/fwlink/p/?LinkId=262039
[Live SDK for Windows]: http://go.microsoft.com/fwlink/p/?LinkId=262253
[Get started with Mobile Services]: mobile-services-dotnet-backend-windows-store-dotnet-get-started.md
[Get started with data]: mobile-services-dotnet-backend-windows-universal-dotnet-get-started-data.md
[Get started with authentication]: mobile-services-dotnet-backend-windows-universal-dotnet-get-started-users.md
[Send push notifications to authenticated users]: mobile-services-dotnet-backend-windows-store-dotnet-push-notifications-app-users.md
[What are Notification Hubs?]: https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-push-notification-overview/
[How to use a .NET client for Azure Mobile Services]: mobile-services-windows-dotnet-how-to-use-client-library.md
[MobileServiceClient]: http://msdn.microsoft.com/library/azure/microsoft.windowsazure.mobileservices.mobileserviceclient.aspx
================================================
FILE: docs/mobile-services-dotnet-backend-windows-universal-dotnet-get-started-users.md
================================================
# Add authentication to your Mobile Services app
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-users.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started-users.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-users.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-get-started-users.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-windows-phone-get-started-users.md)
- [(Android | Javascript)](mobile-services-android-get-started-users.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started-users.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-users.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-users.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-users.md)
- [(HTML | Javascript)](mobile-services-html-get-started-users.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
## Overview
This topic shows you how to authenticate users in Azure Mobile Services from your universal Windows app. In this tutorial, you add authentication to the quickstart project using an identity provider that is supported by Mobile Services. After being successfully authenticated and authorized by Mobile Services, the user ID value is displayed.
This tutorial is based on the Mobile Services quickstart. You must also first complete the tutorial [Get started with Mobile Services] or [Add Mobile Services to an existing app](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-data.md).
>[AZURE.NOTE]This tutorial shows you how to use server-directed authentication for users in Windows Store and Windows Phone Store 8.1 apps. Fore information about client-directed authentication, see [Logging in with Google, Microsoft and Facebook SDKs to Azure Mobile Services](https://azure.microsoft.com/blog/2014/10/27/logging-in-with-google-microsoft-and-facebook-sdks-to-azure-mobile-services/).
## Register your app for authentication and configure Mobile Services
1. In the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Dashboard**, and make a note of the **Mobile Service URL** value.
2. Register your app with one or more of the following authentication providers:
* [Google](./
mobile-services-how-to-register-google-authentication.md)
* [Facebook](./
mobile-services-how-to-register-facebook-authentication.md)
* [Twitter](./
mobile-services-how-to-register-twitter-authentication.md)
* [Microsoft](./
mobile-services-how-to-register-microsoft-authentication.md)
* [Azure Active Directory](./
mobile-services-how-to-register-active-directory-authentication.md).
Make a note of the client identity and client secret values generated by the provider. Do not distribute or share the client secret.
3. Back in the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Identity** > your identity provider settings, then enter the client ID and secret value from your provider.
You've now configured both your app and your mobile service to work with your auth provider. You may optionally repeat all these steps for each additional identity provider you'd like to support.
> [AZURE.IMPORTANT] Verify that you've set the correct redirect URI on your identity provider's developer site. As described in the linked instructions for each provider above, the redirect URI may be different for a .NET backend service vs. for a JavaScript backend service. An incorrectly configured redirect URI may result in the login screen not being displayed properly and the app malfunctioning in unexpected ways.
### (Optional) Configure your .NET Mobile Service for Azure Active Directory
>[AZURE.NOTE] These steps are optional because they only apply to the Azure Active Directory login provider.
1. Install the [WindowsAzure.MobileServices.Backend.Security NuGet package](https://www.nuget.org/packages/WindowsAzure.MobileServices.Backend.Security).
2. In Visual Studio expand App_Start and open WebApiConfig.cs. Add the following `using` statement at the top:
using Microsoft.WindowsAzure.Mobile.Service.Security.Providers;
3. Also in WebApiConfig.cs, add the following code to the `Register` method, immediately after `options` is instantiated:
options.LoginProviders.Remove(typeof(AzureActiveDirectoryLoginProvider));
options.LoginProviders.Add(typeof(AzureActiveDirectoryExtendedLoginProvider));
## Restrict permissions to authenticated users
By default, all requests to mobile service resources are restricted to clients that present the application key, which does not strictly secure access to resources. To secure your resources, you must restrict access to only authenticated clients.
1. In Visual Studio, open your mobile service project, expand the Controllers folder, and open **TodoItemController.cs**. The **TodoItemController** class implements data access for the TodoItem table. Add the following `using` statement:
using Microsoft.WindowsAzure.Mobile.Service.Security;
2. Apply the following _AuthorizeLevel_ attribute to the **TodoItemController** class.
[AuthorizeLevel(AuthorizationLevel.User)]
This makes sure that all operations against the _TodoItem_ table require an authenticated user. You can also apply the *AuthorizeLevel* attribute at the method level.
3. (Optional) If you wish to debug authentication locally, expand the `App_Start` folder, open **WebApiConfig.cs**, and add the following code to the **Register** method.
config.SetIsHosted(true);
This tells the local mobile service project to run as if it is being hosted in Azure, including honoring the *AuthorizeLevel* settings. Without this setting, all HTTP requests to localhost are permitted without authentication despite the *AuthorizeLevel* setting. When you enable self-hosted mode, you also need to set a value for the local application key.
4. (Optional) In the web.config project file, set a string value for the `MS_ApplicationKey` app setting.
This is the password that you use (with no username) to test the API help pages when you run the service locally. This string value is not used by the live site in Azure, and you do not need to use the actual application key; any valid string value will work.
4. Republish your project.
6. In Visual Studio, right-click the Windows Store project for the TodoList app and click **Set as StartUp Project**.
7. In the shared project, open the App.xaml.cs project file, locate the definition for the [MobileServiceClient](http://msdn.microsoft.com/library/azure/microsoft.windowsazure.mobileservices.mobileserviceclient.aspx), and make sure that it is configured to connect to the mobile service running in Azure.
>[AZURE.NOTE]When you use Visual Studio tools to connect your app to a Mobile Service, the tool generate two sets of **MobileServiceClient** definitions, one for each client platform. This is a good time to simplify the generated code by unifying the `#if...#endif` wrapped **MobileServiceClient** definitions into a single unwrapped definition used by both versions of the app. You won't need to do this when you downloaded the quickstart app from the [Azure classic portal].
8. Press the F5 key to run the Windows store app, and verify that an unhandled exception with a status code of 401 (Unauthorized) is raised after the app starts.
This happens because the app attempts to access Mobile Services as an unauthenticated user, but the *TodoItem* table now requires authentication.
Next, you will update the app to authenticate users before requesting resources from the mobile service.
## Add authentication to the app
## Install the storage client in the mobile service project
To be able to generate an SAS to upload images to Blob storage, you must first add the NuGet package that installs Storage client library in the mobile service project.
1. In **Solution Explorer** in Visual Studio, right-click the mobile service project, and then select **Manage NuGet Packages**.
2. In the left pane, select the **Online** category, select **Stabile Only**, search for **WindowsAzure.Storage**, click **Install** on the **Azure Storage** package, then accept the license agreements.

This adds the client library for Azure storage services to the mobile service project.
1. Open the shared project file MainPage.cs and add the following code snippet to the MainPage class:
// Define a member variable for storing the signed-in user.
private MobileServiceUser user;
// Define a method that performs the authentication process
// using a Facebook sign-in.
private async System.Threading.Tasks.Task AuthenticateAsync()
{
string message;
bool success = false;
try
{
// Change 'MobileService' to the name of your MobileServiceClient instance.
// Sign-in using Facebook authentication.
user = await App.MobileService
.LoginAsync(MobileServiceAuthenticationProvider.Facebook);
message =
string.Format("You are now signed in - {0}", user.UserId);
success = true;
}
catch (InvalidOperationException)
{
message = "You must log in. Login Required";
}
var dialog = new MessageDialog(message);
dialog.Commands.Add(new UICommand("OK"));
await dialog.ShowAsync();
return success;
}
This code authenticates the user with a Facebook login. If you are using an identity provider other than Facebook, change the value of **MobileServiceAuthenticationProvider** above to the value for your provider.
3. Comment-out or delete the call to the **RefreshTodoItems** method in the existing **OnNavigatedTo** method override.
This prevents the data from being loaded before the user is authenticated. Next, you will add a **Sign in** button to the app that triggers authentication.
4. Add the following code snippet to the MainPage class:
private async void ButtonLogin_Click(object sender, RoutedEventArgs e)
{
// Login the user and then load data from the mobile app.
if (await AuthenticateAsync())
{
// Hide the login button and load items from the mobile app.
ButtonLogin.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
//await InitLocalStoreAsync(); //offline sync support.
await RefreshTodoItems();
}
}
5. In the Windows Store app project, open the MainPage.xaml project file and add the following **Button** element just before the element that defines the **Save** button:
6. In the Windows Phone Store app project, add the following **Button** element in the **ContentPanel**, after the **TextBox** element:
8. Open the shared App.xaml.cs project file and add the following code:
protected override void OnActivated(IActivatedEventArgs args)
{
// Windows Phone 8.1 requires you to handle the respose from the WebAuthenticationBroker.
#if WINDOWS_PHONE_APP
if (args.Kind == ActivationKind.WebAuthenticationBrokerContinuation)
{
// Completes the sign-in process started by LoginAsync.
// Change 'MobileService' to the name of your MobileServiceClient instance.
App.MobileService.LoginComplete(args as WebAuthenticationBrokerContinuationEventArgs);
}
#endif
base.OnActivated(args);
}
If the **OnActivated** method already exists, just add the `#if...#endif` code block.
9. Press the F5 key to run the Windows Store app, click the **Sign in** button, and sign into the app with your chosen identity provider.
When you are successfully logged-in, the app should run without errors, and you should be able to query your backend and make updates to data.
10. Right-click the Windows Phone Store app project, click **Set as StartUp Project**, then repeat the previous step to verify that the Windows Phone Store app also runs correctly.
>[AZURE.NOTE]If you registered your Windows Store app package information with Mobile Services, you should call the LoginAsync method by supplying a value of **true** for the *useSingleSignOn* parameter. If you do not do this, your users will continue to be presented with a login prompt every time that the login method is called.
## Store the authorization tokens on the client
The previous example showed a standard sign-in, which requires the client to contact both the identity provider and the mobile service every time that the app starts. Not only is this method inefficient, you can run into usage-related issues should many customers try to start your app at the same time. A better approach is to cache the authorization token returned by Mobile Services and try to use this first before using a provider-based sign-in.
>[AZURE.NOTE]You can cache the token issued by Mobile Services regardless of whether you are using client-managed or service-managed authentication. This tutorial uses service-managed authentication.
1. In the MainPage.xaml.cs project file, add the following **using** statements:
using System.Linq;
using Windows.Security.Credentials;
2. Replace the **AuthenticateAsync** method with the following code:
private async System.Threading.Tasks.Task AuthenticateAsync()
{
string message;
bool success = false;
// This sample uses the Facebook provider.
var provider = MobileServiceAuthenticationProvider.Facebook;
// Use the PasswordVault to securely store and access credentials.
PasswordVault vault = new PasswordVault();
PasswordCredential credential = null;
try
{
// Try to get an existing credential from the vault.
credential = vault.FindAllByResource(provider.ToString()).FirstOrDefault();
}
catch (Exception)
{
// When there is no matching resource an error occurs, which we ignore.
}
if (credential != null)
{
// Create a user from the stored credentials.
user = new MobileServiceUser(credential.UserName);
credential.RetrievePassword();
user.MobileServiceAuthenticationToken = credential.Password;
// Set the user from the stored credentials.
App.MobileService.CurrentUser = user;
// Consider adding a check to determine if the token is
// expired, as shown in this post: http://aka.ms/jww5vp.
success = true;
message = string.Format("Cached credentials for user - {0}", user.UserId);
}
else
{
try
{
// Login with the identity provider.
user = await App.MobileService
.LoginAsync(provider);
// Create and store the user credentials.
credential = new PasswordCredential(provider.ToString(),
user.UserId, user.MobileServiceAuthenticationToken);
vault.Add(credential);
success = true;
message = string.Format("You are now logged in - {0}", user.UserId);
}
catch (MobileServiceInvalidOperationException)
{
message = "You must log in. Login Required";
}
}
var dialog = new MessageDialog(message);
dialog.Commands.Add(new UICommand("OK"));
await dialog.ShowAsync();
return success;
}
In this version of **AuthenticateAsync**, the app tries to use credentials stored in the **PasswordVault** to access the service. A regular sign-in is also performed when there is no stored credential.
>[AZURE.NOTE]A cached token may be expired, and token expiration can also occur after authentication when the app is in use. To learn how to determine if a token is expired, see [Check for expired authentication tokens](http://aka.ms/jww5vp). For a solution to handling authorization errors related to expiring tokens, see the post [Caching and handling expired tokens in Azure Mobile Services managed SDK](http://blogs.msdn.com/b/carlosfigueira/archive/2014/03/13/caching-and-handling-expired-tokens-in-azure-mobile-services-managed-sdk.aspx).
3. Restart the app twice.
Notice that on the first start-up, sign-in with the provider is again required. However, on the second restart the cached credentials are used and sign-in is bypassed.
## Next steps
In the next tutorial, [Service-side authorization of Mobile Services users][Authorize users with scripts], you will take the user ID value provided by Mobile Services based on an authenticated user and use it to filter the data returned by Mobile Services.
## See also
+ [Enhanced users feature](https://azure.microsoft.com/blog/2014/10/02/custom-login-scopes-single-sign-on-new-asp-net-web-api-updates-to-the-azure-mobile-services-net-backend/)
You can get additional user data maintained by the identity provider in your mobile service by by calling the **ServiceUser.GetIdentitiesAsync()** method in a .NET backend.
+ [Mobile Services .NET How-to Conceptual Reference] Learn more about how to use Mobile Services with a .NET client.
[Register your app for authentication and configure Mobile Services]: #register
[Restrict table permissions to authenticated users]: #permissions
[Add authentication to the app]: #add-authentication
[Store authentication tokens on the client]: #tokens
[Next Steps]:#next-steps
[Submit an app page]: http://go.microsoft.com/fwlink/p/?LinkID=266582
[My Applications]: http://go.microsoft.com/fwlink/p/?LinkId=262039
[Live SDK for Windows]: http://go.microsoft.com/fwlink/p/?LinkId=262253
[Get started with Mobile Services]: mobile-services-dotnet-backend-windows-store-dotnet-get-started.md
[Get started with data]: mobile-services-dotnet-backend-windows-store-dotnet-get-started-data.md
[Get started with authentication]: mobile-services-dotnet-backend-windows-store-dotnet-get-started-users.md
[Get started with push notifications]: mobile-services-dotnet-backend-windows-store-dotnet-get-started-push.md
[Authorize users with scripts]: mobile-services-dotnet-backend-service-side-authorization.md
[JavaScript and HTML]: mobile-services-dotnet-backend-windows-store-javascript-get-started-users.md
[Azure classic portal]: https://manage.windowsazure.com/
[Mobile Services .NET How-to Conceptual Reference]: mobile-services-windows-dotnet-how-to-use-client-library.md
[Register your Windows Store app package for Microsoft authentication]: mobile-services-how-to-register-store-app-package-microsoft-authentication.md
================================================
FILE: docs/mobile-services-dotnet-backend-windows-universal-dotnet-upload-data-blob-storage.md
================================================
# Upload images to Azure Storage by using Mobile Services
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
> [AZURE.SELECTOR-LIST (Platform | Backend)]
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-upload-data-blob-storage.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-upload-data-blob-storage.md)
- [(Android | Javascript)](mobile-services-android-upload-data-blob-storage.md)
## Overview
This topic shows you how to use Azure Mobile Services to enable your app to upload and store user-generated images in Azure Storage. Mobile Services uses a SQL Database to store data. However, binary large object (BLOB) data is more efficiently stored in Azure Blob storage service.
You cannot securely distribute with the client app the credentials required to securely upload data to the Blob Storage service. Instead, you must store these credentials in your mobile service and use them to generate a Shared Access Signature (SAS) that is used to upload a new image. The SAS, a credential with a short expiration—in this case 5 minutes, is returned securely by Mobile Services to the client app. The app then uses this temporary credential to upload the image. In this example, downloads from the Blob service are public.
In this tutorial you add functionality to the Mobile Services quickstart app to take pictures and upload the images to Azure by using an SAS generated by Mobile Services.
## Prerequisites
This tutorial requires the following:
+ Microsoft Visual Studio 2013 Update 3, or a later version.
+ [Azure Storage account](https://azure.microsoft.com/en-us/documentation/articles/storage-create-storage-account/)
+ A camera or other image capture device attached to your computer.
This tutorial is based on the Mobile Services quickstart. Before you start this tutorial, you must first complete [Get started with Mobile Services].
## Install the storage client in the mobile service project
To be able to generate an SAS to upload images to Blob storage, you must first add the NuGet package that installs Storage client library in the mobile service project.
1. In **Solution Explorer** in Visual Studio, right-click the mobile service project, and then select **Manage NuGet Packages**.
2. In the left pane, select the **Online** category, select **Stabile Only**, search for **WindowsAzure.Storage**, click **Install** on the **Azure Storage** package, then accept the license agreements.

This adds the client library for Azure storage services to the mobile service project.
## Update the TodoItem definition in the data model
The TodoItem class defines the data object, and you need to add the same properties to this class as you did on the client.
1. In Visual Studio 2013, open your mobile service project, expand the DataObjects folder, then open the TodoItem.cs project file.
2. Add the following new properties to the **TodoItem** class:
public string containerName { get; set; }
public string resourceName { get; set; }
public string sasQueryString { get; set; }
public string imageUri { get; set; }
These properties are used to generate the SAS and to store image information. Note that the casing on these properties matches the JavaScript backend version.
>[AZURE.NOTE] When using the default database initializer, Entity Framework will drop and recreate the database when it detects a data model change in the Code First definition. To make this data model change and maintain existing data in the database, you must use Code First Migrations. The default initializer cannot be used against a SQL Database in Azure. For more information, see [How to Use Code First Migrations to Update the Data Model](mobile-services-dotnet-backend-how-to-use-code-first-migrations.md).
## Update the TodoItem controller to generate a shared access signature
The existing **TodoItemController** is updated so that the **PostTodoItem** method generates an SAS when a new TodoItem is inserted. You also
0. If you haven't yet created your storage account, see [How To Create a Storage Account].
1. In the [Azure classic portal](https://manage.windowsazure.com/), click **Storage**, click the storage account, then click **Manage Keys**.
2. Make a note of the **Storage Account Name** and **Access Key**.
3. In your mobile service, click the **Configure** tab, scroll down to **App settings** and enter a **Name** and **Value** pair for each of the following that you obtained from the storage account, then click **Save**.
+ `STORAGE_ACCOUNT_NAME`
+ `STORAGE_ACCOUNT_ACCESS_KEY`

The storage account access key is stored encrypted in app settings. You can access this key from any server script at runtime. For more information, see [App settings].
4. In Solution Explorer in Visual Studio, open the Web.config file for the mobile service project and add the following new app settings, replacing the placeholders with the storage account name and access key that you just set in the portal:
The mobile service uses these stored settings when it runs on the local computer, which lets you test the code before you publish it. When running in Azure, the mobile service instead uses app settings values set in the portal and ignores these project settings.
7. In the Controllers folder, open the TodoItemController.cs file and add the following **using** directives:
using System;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Blob;
8. Replace the existing **PostTodoItem** method with the following code:
public async Task PostTodoItem(TodoItem item)
{
string storageAccountName;
string storageAccountKey;
// Try to get the Azure storage account token from app settings.
if (!(Services.Settings.TryGetValue("STORAGE_ACCOUNT_NAME", out storageAccountName) |
Services.Settings.TryGetValue("STORAGE_ACCOUNT_ACCESS_KEY", out storageAccountKey)))
{
Services.Log.Error("Could not retrieve storage account settings.");
}
// Set the URI for the Blob Storage service.
Uri blobEndpoint = new Uri(string.Format("https://{0}.blob.core.windows.net", storageAccountName));
// Create the BLOB service client.
CloudBlobClient blobClient = new CloudBlobClient(blobEndpoint,
new StorageCredentials(storageAccountName, storageAccountKey));
if (item.containerName != null)
{
// Set the BLOB store container name on the item, which must be lowercase.
item.containerName = item.containerName.ToLower();
// Create a container, if it doesn't already exist.
CloudBlobContainer container = blobClient.GetContainerReference(item.containerName);
await container.CreateIfNotExistsAsync();
// Create a shared access permission policy.
BlobContainerPermissions containerPermissions = new BlobContainerPermissions();
// Enable anonymous read access to BLOBs.
containerPermissions.PublicAccess = BlobContainerPublicAccessType.Blob;
container.SetPermissions(containerPermissions);
// Define a policy that gives write access to the container for 5 minutes.
SharedAccessBlobPolicy sasPolicy = new SharedAccessBlobPolicy()
{
SharedAccessStartTime = DateTime.UtcNow,
SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(5),
Permissions = SharedAccessBlobPermissions.Write
};
// Get the SAS as a string.
item.sasQueryString = container.GetSharedAccessSignature(sasPolicy);
// Set the URL used to store the image.
item.imageUri = string.Format("{0}{1}/{2}", blobEndpoint.ToString(),
item.containerName, item.resourceName);
}
// Complete the insert operation.
TodoItem current = await InsertAsync(item);
return CreatedAtRoute("Tables", new { id = current.Id }, current);
}
This POST method now generates a new SAS for the inserted item, which is valid for 5 minutes, and assigns the value of the generated SAS to the `sasQueryString` property of the returned item. The `imageUri` property is also set to the resource path of the new BLOB to enable image display during binding in the client UI.
>[AZURE.NOTE] This code creates an SAS for an individual BLOB. If you need to upload multiple blobs to a container using the same SAS, you can instead call the generateSharedAccessSignature method with an empty blob resource name, like this:
Next, you will update the quickstart app to add image upload functionality by using the SAS generated on insert.
[How To Create a Storage Account]: https://azure.microsoft.com/en-us/documentation/articles/storage-create-storage-account/
[App settings]: http://msdn.microsoft.com/library/windowsazure/b6bb7d2d-35ae-47eb-a03f-6ee393e170f7
## Install the Storage client for Windows Store apps
To be able to use an SAS to upload images to Blob storage, you must first add the NuGet package that installs Storage client library for Windows Store apps.
1. In **Solution Explorer** in Visual Studio, right-click the project name, and then select **Manage NuGet Packages**.
2. In the left pane, select the **Online** category, search for `WindowsAzure.Storage`, click **Install** on the **Azure Storage** package, then accept the license agreements.

This adds the client library for Azure storage services to the project.
Next, you will update the quickstart app to capture and upload images.
## Update the quickstart client app to capture and upload images
1. In Visual Studio, open the Package.appxmanifest file for the Windows app project and in the **Capabilities** tab enable the **Webcam** and **Microphone** capabilities.

This makes sure that your app can use a camera attached to the computer. Users will be requested to allow camera access the first time that the app is run.
2. Repeat the step above for the Windows Phone app project.
3. In the Windows app project, open the MainPage.xaml file and replace the **StackPanel** element directly after the first **QuickStartTask** element with the following code:
2. Replace the **StackPanel** element in the **DataTemplate** with the following code:
This adds an image to the **ItemTemplate** and sets its binding source as the URI of the uploaded image in the Blob Storage service.
3. In the Windows Phone app project, open the MainPage.xaml file and replace the **ButtonSave** element with the following code:
2. Replace the **StackPanel** element in the **DataTemplate** with the following code:
4. In the shared DataModel folder, open the TodoItem.cs project file and add add the following properties to the TodoItem class:
[JsonProperty(PropertyName = "containerName")]
public string ContainerName { get; set; }
[JsonProperty(PropertyName = "resourceName")]
public string ResourceName { get; set; }
[JsonProperty(PropertyName = "sasQueryString")]
public string SasQueryString { get; set; }
[JsonProperty(PropertyName = "imageUri")]
public string ImageUri { get; set; }
3. Open the shared MainPage.cs project file and add the following **using** statements:
using Windows.Media.Capture;
using Windows.Media.MediaProperties;
using Windows.Storage;
using Windows.UI.Xaml.Input;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Blob;
using Windows.UI.Xaml.Media.Imaging;
5. Add the following code to the MainPage class:
// Use a StorageFile to hold the captured image for upload.
StorageFile media = null;
MediaCapture cameraCapture;
bool IsCaptureInProgress;
private async Task CaptureImage()
{
// Capture a new photo or video from the device.
cameraCapture = new MediaCapture();
cameraCapture.Failed += cameraCapture_Failed;
// Initialize the camera for capture.
await cameraCapture.InitializeAsync();
#if WINDOWS_PHONE_APP
cameraCapture.SetPreviewRotation(VideoRotation.Clockwise90Degrees);
cameraCapture.SetRecordRotation(VideoRotation.Clockwise90Degrees);
#endif
captureGrid.Visibility = Windows.UI.Xaml.Visibility.Visible;
previewElement.Visibility = Windows.UI.Xaml.Visibility.Visible;
previewElement.Source = cameraCapture;
await cameraCapture.StartPreviewAsync();
}
private async void previewElement_Tapped(object sender, TappedRoutedEventArgs e)
{
// Block multiple taps.
if (!IsCaptureInProgress)
{
IsCaptureInProgress = true;
// Create the temporary storage file.
media = await ApplicationData.Current.LocalFolder
.CreateFileAsync("capture_file.jpg", CreationCollisionOption.ReplaceExisting);
// Take the picture and store it locally as a JPEG.
await cameraCapture.CapturePhotoToStorageFileAsync(
ImageEncodingProperties.CreateJpeg(), media);
captureButtons.Visibility = Visibility.Visible;
// Use the stored image as the preview source.
BitmapImage tempBitmap = new BitmapImage(new Uri(media.Path));
imagePreview.Source = tempBitmap;
imagePreview.Visibility = Visibility.Visible;
previewElement.Visibility = Visibility.Collapsed;
IsCaptureInProgress = false;
}
}
private async void cameraCapture_Failed(MediaCapture sender, MediaCaptureFailedEventArgs errorEventArgs)
{
// It's safest to return this back onto the UI thread to show the message dialog.
MessageDialog dialog = new MessageDialog(errorEventArgs.Message);
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
async () => { await dialog.ShowAsync(); });
}
private async void ButtonCapture_Click(object sender, RoutedEventArgs e)
{
// Prevent multiple initializations.
ButtonCapture.IsEnabled = false;
await CaptureImage();
}
private async void ButtonRetake_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
// Reset the capture and then start again.
await ResetCaptureAsync();
await CaptureImage();
}
private async void ButtonCancel_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
await ResetCaptureAsync();
}
private async Task ResetCaptureAsync()
{
captureGrid.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
imagePreview.Visibility = Visibility.Collapsed;
captureButtons.Visibility = Visibility.Collapsed;
previewElement.Source = null;
ButtonCapture.IsEnabled = true;
// Make sure we stop the preview and release resources.
await cameraCapture.StopPreviewAsync();
cameraCapture.Dispose();
media = null;
}
This code displays the UI used to capture an image, and saves the image to a storage file.
6. Replace the existing `InsertTodoItem` method with the following code:
private async Task InsertTodoItem(TodoItem todoItem)
{
string errorString = string.Empty;
if (media != null)
{
// Set blob properties of TodoItem.
todoItem.ContainerName = "todoitemimages";
// Use a unigue GUID to avoid collisions.
todoItem.ResourceName = Guid.NewGuid().ToString();
}
// Send the item to be inserted. When blob properties are set this
// generates an SAS in the response.
await todoTable.InsertAsync(todoItem);
// If we have a returned SAS, then upload the blob.
if (!string.IsNullOrEmpty(todoItem.SasQueryString))
{
// Get the URI generated that contains the SAS
// and extract the storage credentials.
StorageCredentials cred = new StorageCredentials(todoItem.SasQueryString);
var imageUri = new Uri(todoItem.ImageUri);
// Instantiate a Blob store container based on the info in the returned item.
CloudBlobContainer container = new CloudBlobContainer(
new Uri(string.Format("https://{0}/{1}",
imageUri.Host, todoItem.ContainerName)), cred);
// Get the new image as a stream.
using (var inputStream = await media.OpenReadAsync())
{
// Upload the new image as a BLOB from the stream.
CloudBlockBlob blobFromSASCredential =
container.GetBlockBlobReference(todoItem.ResourceName);
await blobFromSASCredential.UploadFromStreamAsync(inputStream);
}
// When you request an SAS at the container-level instead of the blob-level,
// you are able to upload multiple streams using the same container credentials.
await ResetCaptureAsync();
}
// Add the new item to the collection.
items.Add(todoItem);
}
This code sends a request to the mobile service to insert a new TodoItem. The response contains the SAS, which is then used to upload the image from local storage to Azure Blob storage. The URL of the uploaded image is used in data binding.
The final step is to test both versions of the app and validate that uploads succeed from both devices.
## Test uploading the images in your app
1. In Visual Studio, make sure that the Windows project is set as the default project, then press the F5 key to run the app.
2. Enter text in the textbox under **Insert a TodoItem**, then click **Photo**.
3. Click or tap the preview to take a picture, then click **Upload** to insert the new item and upload the image.

4. The new item, along with the uploaded image, is displayed in the list view.

>[AZURE.NOTE]The image is downloaded automatically from Blob storage when the *imageUri* property of the new item is bound to the **Image** control.
5. Stop the app and restart the Windows Phone project version of the app.
The previously uploaded image is displayed.
6. As before, enter some text in the textbox, then click **Photo**.

3. Tap the preview to take a picture, then click **Upload** to insert the new item and upload the image.

You have completed the upload images tutorial.
## Next steps
Now that you have been able to securely upload images by integrating your mobile service with the Blob service, check out some of the other backend service and integration topics:
+ [Schedule backend jobs in Mobile Services](mobile-services-dotnet-backend-schedule-recurring-tasks.md)
Learn how to use the Mobile Services job scheduler functionality to define server script code that is executed on a schedule that you define.
+ [Mobile Services .NET How-to Conceptual Reference](mobile-services-dotnet-how-to-use-client-library.md)
Learn more about how to use Mobile Services with .NET
[Install the Storage Client library]: #install-storage-client
[Update the client app to capture images]: #add-select-images
[Install the storage client in the mobile service project]: #storage-client-server
[Update the TodoItem definition in the data model]: #update-data-model
[Update the table controller to generate an SAS]: #update-scripts
[Upload images to test the app]: #test
[Next Steps]:#next-steps
[Get started with Mobile Services]: mobile-services-windows-store-dotnet-get-started.md
[How To Create a Storage Account]: https://azure.microsoft.com/en-us/documentation/articles/storage-create-storage-account/
[Azure Storage Client library for Store apps]: http://go.microsoft.com/fwlink/p/?LinkId=276866
================================================
FILE: docs/mobile-services-dotnet-backend-xamarin-android-get-started-push.md
================================================
# Add push notifications to your Mobile Services app
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-push.md)
- [(iOS | JavaScript)](mobile-services-javascript-backend-ios-get-started-push.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-push.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-get-started-push.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-javascript-backend-windows-phone-get-started-push.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started-push.md)
- [(Android | Javascript)](mobile-services-javascript-backend-android-get-started-push.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-push.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-push.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-push.md)
- [(Xamarin.Forms | JavaScript)](partner-xamarin-mobile-services-xamarin-forms-get-started-push.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
## Overview
This topic shows you how to use Azure Mobile Services to send push notifications to a Xamarin.Android app. In this tutorial you add push notifications using the Google Cloud Messaging (GCM) service to the [Get started with Mobile Services] project. When complete, your mobile service will send a push notification each time a record is inserted.
This tutorial requires the following:
+ An active Google account.
+ [Google Cloud Messaging Client Component]. You will add this component during the tutorial.
You should already have the Xamarin.Android and [Azure Mobile Services][Azure Mobile Services Component] components installed in your project from when you completed [Get started with Mobile Services].
## Enable Google Cloud Messaging
1. Navigate to the [Google Cloud Console](https://console.developers.google.com/project), sign in with your Google account credentials.
2. Click **Create Project**, type a project name, then click **Create**. If requested, carry out the SMS Verification, and click **Create** again.

Type in your new **Project name** and click **Create project**.
3. Click the **Utilities and More** button and then click **Project Information**. Make a note of the **Project Number**. You will need to set this value as the `SenderId` variable in the client app.

4. In the project dashboard, under **Mobile APIs**, click **Google Cloud Messaging**, then on the next page click **Enable API** and accept the terms of service.


5. In the project dashboard, Click **Credentials** > **Create Credential** > **API Key**.

6. In **Create a new key**, click **Server key**, type a name for your key, then click **Create**.
7. Make a note of the **API KEY** value.
You will use this API key value to enable Azure to authenticate with GCM and send push notifications on behalf of your app.
## Configure your mobile service to send push requests
1. Log on to the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services**, and then click your app.
2. Click the **Push** tab, enter the **API Key** value obtained from GCM in the previous procedure, then click **Save**.

>[AZURE.NOTE]When you set your GCM credentials for enhanced push notifications in the Push tab in the portal, they are shared with Notification Hubs to configure the notification hub with your app.
Both your mobile service and your app are now configured to work with GCM and Notification Hubs.
## Update the mobile service to send push notifications
1. In Visual Studio Solution Explorer, expand the **Controllers** folder in the mobile service project. Open TodoItemController.cs. At the top of the file, add the following `using` statements:
using System;
using System.Collections.Generic;
2. Update the `PostTodoItem` method definition with the following code:
public async Task PostTodoItem(TodoItem item)
{
TodoItem current = await InsertAsync(item);
Dictionary data = new Dictionary()
{
{ "message", item.Text}
};
GooglePushMessage message = new GooglePushMessage(data, TimeSpan.FromHours(1));
try
{
var result = await Services.Push.SendAsync(message);
Services.Log.Info(result.State.ToString());
}
catch (System.Exception ex)
{
Services.Log.Error(ex.Message, null, "Push.SendAsync Error");
}
return CreatedAtRoute("Tables", new { id = current.Id }, current);
}
This code will send a push notification (with the text of the inserted item) after inserting a todo item. In the event of an error, the code will add an error log entry which is viewable on the **Logs** tab of the mobile service in the [Azure classic portal](https://manage.windowsazure.com/).
3. Republish your mobile service project to Azure.
## Configure the existing project for push notifications
1. In the Solution view (or **Solution Explorer** in Visual Studio), right-click the **Components** folder, click **Get More Components...**, search for the **Google Cloud Messaging Client** component and add it to the project.
2. Open the ToDoActivity.cs project file and add the following using statement to the class:
using Gcm.Client;
3. In the **ToDoActivity** class, add the following new code:
// Create a new instance field for this activity.
static ToDoActivity instance = new ToDoActivity();
// Return the current activity instance.
public static ToDoActivity CurrentActivity
{
get
{
return instance;
}
}
// Return the Mobile Services client.
public MobileServiceClient CurrentClient
{
get
{
return client;
}
}
This enables you to access the mobile client instance from the push handler service process.
4. Add the following code to the **OnCreate** method, after the **MobileServiceClient** is created:
// Set the current instance of TodoActivity.
instance = this;
// Make sure the GCM client is set up correctly.
GcmClient.CheckDevice(this);
GcmClient.CheckManifest(this);
// Register the app for push notifications.
GcmClient.Register(this, ToDoBroadcastReceiver.senderIDs);
Your **ToDoActivity** is now prepared for adding push notifications.
## Add push notifications code to your app
4. Create a new class in the project called `ToDoBroadcastReceiver`.
5. Add the following using statements to **ToDoBroadcastReceiver** class:
using Gcm.Client;
using Microsoft.WindowsAzure.MobileServices;
6. Add the following permission requests between the **using** statements and the **namespace** declaration:
[assembly: Permission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "com.google.android.c2dm.permission.RECEIVE")]
//GET_ACCOUNTS is only needed for android versions 4.0.3 and below
[assembly: UsesPermission(Name = "android.permission.GET_ACCOUNTS")]
[assembly: UsesPermission(Name = "android.permission.INTERNET")]
[assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
7. Replace the existing **ToDoBroadcastReceiver** class definition with the following:
[BroadcastReceiver(Permission = Gcm.Client.Constants.PERMISSION_GCM_INTENTS)]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_MESSAGE },
Categories = new string[] { "@PACKAGE_NAME@" })]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_REGISTRATION_CALLBACK },
Categories = new string[] { "@PACKAGE_NAME@" })]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_LIBRARY_RETRY },
Categories = new string[] { "@PACKAGE_NAME@" })]
public class ToDoBroadcastReceiver : GcmBroadcastReceiverBase
{
// Set the Google app ID.
public static string[] senderIDs = new string[] { "" };
}
In the above code, you must replace _``_ with the project number assigned by Google when you provisioned your app in the Google developer portal.
8. In the ToDoBroadcastReceiver.cs project file, add the following code that defines the **PushHandlerService** class:
// The ServiceAttribute must be applied to the class.
[Service]
public class PushHandlerService : GcmServiceBase
{
public static string RegistrationID { get; private set; }
public PushHandlerService() : base(ToDoBroadcastReceiver.senderIDs) { }
}
Note that this class derives from **GcmServiceBase** and that the **Service** attribute must be applied to this class.
>[AZURE.NOTE]The **GcmServiceBase** class implements the **OnRegistered()**, **OnUnRegistered()**, **OnMessage()** and **OnError()** methods. You must override these methods in the **PushHandlerService** class.
5. Add the following code to the **PushHandlerService** class that overrides the **OnRegistered** event handler.
protected override void OnRegistered(Context context, string registrationId)
{
System.Diagnostics.Debug.WriteLine("The device has been registered with GCM.", "Success!");
// Get the MobileServiceClient from the current activity instance.
MobileServiceClient client = ToDoActivity.CurrentActivity.CurrentClient;
var push = client.GetPush();
List tags = null;
//// (Optional) Uncomment to add tags to the registration.
//var tags = new List() { "myTag" }; // create tags if you want
try
{
// Make sure we run the registration on the same thread as the activity,
// to avoid threading errors.
ToDoActivity.CurrentActivity.RunOnUiThread(
async () => await push.RegisterNativeAsync(registrationId, tags));
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(
string.Format("Error with Azure push registration: {0}", ex.Message));
}
}
This method uses the returned GCM registration ID to register with Azure for push notifications.
10. Override the **OnMessage** method in **PushHandlerService** with the following code:
protected override void OnMessage(Context context, Intent intent)
{
string message = string.Empty;
// Extract the push notification message from the intent.
if (intent.Extras.ContainsKey("message"))
{
message = intent.Extras.Get("message").ToString();
var title = "New item added:";
// Create a notification manager to send the notification.
var notificationManager =
GetSystemService(Context.NotificationService) as NotificationManager;
// Create a new intent to show the notification in the UI.
PendingIntent contentIntent =
PendingIntent.GetActivity(context, 0,
new Intent(this, typeof(ToDoActivity)), 0);
// Create the notification using the builder.
var builder = new Notification.Builder(context);
builder.SetAutoCancel(true);
builder.SetContentTitle(title);
builder.SetContentText(message);
builder.SetSmallIcon(Resource.Drawable.ic_launcher);
builder.SetContentIntent(contentIntent);
var notification = builder.Build();
// Display the notification in the Notifications Area.
notificationManager.Notify(1, notification);
}
}
12. Override the **OnUnRegistered()** and **OnError()** methods with the following code.
protected override void OnUnRegistered(Context context, string registrationId)
{
throw new NotImplementedException();
}
protected override void OnError(Context context, string errorId)
{
System.Diagnostics.Debug.WriteLine(
string.Format("Error occurred in the notification: {0}.", errorId));
}
## Test the app against the published mobile service
You can test the app by directly attaching an Android phone with a USB cable, or by using a virtual device in the emulator.
### Enable push notifications for local testing
You can optionally test push notifications with your mobile service running on the local computer or VM before you publish to Azure. To do this, you must set information about the notification hub used by your app in the web.config file. This information is only used when running locally to connect to the notification hub; it is ignored when published to Azure.
1. Back in the **Push** tab of your mobile service, click the **Notification Hub** link.

This navigates to the notification hub used by your mobile service.
2. In the notification hub page, make a note of the name of your notification hub, then click **View Connection String**.

3. In the **Access connection information**, copy the **DefaultFullSharedAccessSignature** connection string.

4. In your mobile service project in Visual Studio, open the Web.config file for the service and in **connectionStrings**, replace the connection string for **MS_NotificationHubConnectionString** with the connection string from the previous step.
5. In **appSettings**, replace the value of the **MS_NotificationHubName** app setting with the name of the notification hub.
Now, the mobile service project is configured to connect to the notification hub in Azure when running locally. Note that it is important to use the same notification hub name and connection string as the portal because these Web.config project settings are overridden by the portal settings when running in Azure.
4. Create a new class in the project called `ToDoBroadcastReceiver`.
5. Add the following using statements to **ToDoBroadcastReceiver** class:
using Gcm.Client;
using Microsoft.WindowsAzure.MobileServices;
6. Add the following permission requests between the **using** statements and the **namespace** declaration:
[assembly: Permission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "com.google.android.c2dm.permission.RECEIVE")]
//GET_ACCOUNTS is only needed for android versions 4.0.3 and below
[assembly: UsesPermission(Name = "android.permission.GET_ACCOUNTS")]
[assembly: UsesPermission(Name = "android.permission.INTERNET")]
[assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
7. Replace the existing **ToDoBroadcastReceiver** class definition with the following:
[BroadcastReceiver(Permission = Gcm.Client.Constants.PERMISSION_GCM_INTENTS)]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_MESSAGE },
Categories = new string[] { "@PACKAGE_NAME@" })]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_REGISTRATION_CALLBACK },
Categories = new string[] { "@PACKAGE_NAME@" })]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_LIBRARY_RETRY },
Categories = new string[] { "@PACKAGE_NAME@" })]
public class ToDoBroadcastReceiver : GcmBroadcastReceiverBase
{
// Set the Google app ID.
public static string[] senderIDs = new string[] { "" };
}
In the above code, you must replace _``_ with the project number assigned by Google when you provisioned your app in the Google developer portal.
8. In the ToDoBroadcastReceiver.cs project file, add the following code that defines the **PushHandlerService** class:
// The ServiceAttribute must be applied to the class.
[Service]
public class PushHandlerService : GcmServiceBase
{
public static string RegistrationID { get; private set; }
### Setting up the Android emulator for testing
When you run this app in the emulator, make sure that you use an Android Virtual Device (AVD) that supports Google APIs.
> [AZURE.IMPORTANT] In order to receive push notifications, you must set up a Google account on your Android Virtual Device (in the emulator, navigate to **Settings** and click **Add Account**). Also, make sure that the emulator is connected to the Internet.
1. From **Tools**, click **Open Android Emulator Manager**, select your device, and then click **Edit**.

2. Select **Google APIs** in **Target**, then click **OK**.

3. On the top toolbar, click **Run**, and then select your app. This starts the emulator and runs the app.
The app retrieves the *registrationId* from GCM and registers with the Notification Hub.
### Inserting a new item generates a notification.
1. In the app, type meaningful text, such as _A new Mobile Services task_ and then click the **Add** button.
2. Swipe down from the top of the screen to open the device's Notification Center to see the notification.

[Get started with Mobile Services]: mobile-services-dotnet-backend-xamarin-android-get-started.md
[Google Cloud Messaging Client Component]: http://components.xamarin.com/view/GCMClient/
[Azure Mobile Services Component]: http://components.xamarin.com/view/azure-mobile-services/
================================================
FILE: docs/mobile-services-dotnet-backend-xamarin-android-get-started-users.md
================================================
# Get started with authentication in Mobile Services
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-users.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started-users.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-users.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-get-started-users.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-windows-phone-get-started-users.md)
- [(Android | Javascript)](mobile-services-android-get-started-users.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started-users.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-users.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-users.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-users.md)
- [(HTML | Javascript)](mobile-services-html-get-started-users.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This topic shows you how to authenticate users in Azure Mobile Services from your app. In this tutorial, you add authentication to the quickstart project using an identity provider that is supported by Mobile Services. After being successfully authenticated and authorized by Mobile Services, the user ID value is displayed.
This tutorial walks you through these basic steps to enable authentication in your app:
1. [Register your app for authentication and configure Mobile Services]
2. [Restrict table permissions to authenticated users]
3. [Add authentication to the app]
This tutorial is based on the Mobile Services quickstart. You must also first complete the tutorial [Get started with Mobile Services].
## Register your app for authentication and configure Mobile Services
1. In the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Dashboard**, and make a note of the **Mobile Service URL** value.
2. Register your app with one or more of the following authentication providers:
* [Google](./
mobile-services-how-to-register-google-authentication.md)
* [Facebook](./
mobile-services-how-to-register-facebook-authentication.md)
* [Twitter](./
mobile-services-how-to-register-twitter-authentication.md)
* [Microsoft](./
mobile-services-how-to-register-microsoft-authentication.md)
* [Azure Active Directory](./
mobile-services-how-to-register-active-directory-authentication.md).
Make a note of the client identity and client secret values generated by the provider. Do not distribute or share the client secret.
3. Back in the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Identity** > your identity provider settings, then enter the client ID and secret value from your provider.
You've now configured both your app and your mobile service to work with your auth provider. You may optionally repeat all these steps for each additional identity provider you'd like to support.
> [AZURE.IMPORTANT] Verify that you've set the correct redirect URI on your identity provider's developer site. As described in the linked instructions for each provider above, the redirect URI may be different for a .NET backend service vs. for a JavaScript backend service. An incorrectly configured redirect URI may result in the login screen not being displayed properly and the app malfunctioning in unexpected ways.
### (Optional) Configure your .NET Mobile Service for Azure Active Directory
>[AZURE.NOTE] These steps are optional because they only apply to the Azure Active Directory login provider.
1. Install the [WindowsAzure.MobileServices.Backend.Security NuGet package](https://www.nuget.org/packages/WindowsAzure.MobileServices.Backend.Security).
2. In Visual Studio expand App_Start and open WebApiConfig.cs. Add the following `using` statement at the top:
using Microsoft.WindowsAzure.Mobile.Service.Security.Providers;
3. Also in WebApiConfig.cs, add the following code to the `Register` method, immediately after `options` is instantiated:
options.LoginProviders.Remove(typeof(AzureActiveDirectoryLoginProvider));
options.LoginProviders.Add(typeof(AzureActiveDirectoryExtendedLoginProvider));
## Restrict permissions to authenticated users
By default, all requests to mobile service resources are restricted to clients that present the application key, which does not strictly secure access to resources. To secure your resources, you must restrict access to only authenticated clients.
1. In Visual Studio, open your mobile service project, expand the Controllers folder, and open **TodoItemController.cs**. The **TodoItemController** class implements data access for the TodoItem table. Add the following `using` statement:
using Microsoft.WindowsAzure.Mobile.Service.Security;
2. Apply the following _AuthorizeLevel_ attribute to the **TodoItemController** class.
[AuthorizeLevel(AuthorizationLevel.User)]
This makes sure that all operations against the _TodoItem_ table require an authenticated user. You can also apply the *AuthorizeLevel* attribute at the method level.
3. (Optional) If you wish to debug authentication locally, expand the `App_Start` folder, open **WebApiConfig.cs**, and add the following code to the **Register** method.
config.SetIsHosted(true);
This tells the local mobile service project to run as if it is being hosted in Azure, including honoring the *AuthorizeLevel* settings. Without this setting, all HTTP requests to localhost are permitted without authentication despite the *AuthorizeLevel* setting. When you enable self-hosted mode, you also need to set a value for the local application key.
4. (Optional) In the web.config project file, set a string value for the `MS_ApplicationKey` app setting.
This is the password that you use (with no username) to test the API help pages when you run the service locally. This string value is not used by the live site in Azure, and you do not need to use the actual application key; any valid string value will work.
4. Republish your project.
In Visual Studio or Xamarin Studio, run the client project on a device or simulator. Verify that an unhandled exception with a status code of 401 (Unauthorized) is raised after the app starts.
This happens because the app attempts to access Mobile Services as an unauthenticated user, but the TodoItem table now requires authentication.
Next, you will update the app to authenticate users before requesting resources from the mobile service.
## Add authentication to the app
1. Add the following property to the **TodoActivity** class:
private MobileServiceUser user;
2. Add the following method to the **TodoActivity** class:
private async Task Authenticate()
{
try
{
user = await client.LoginAsync(this, MobileServiceAuthenticationProvider.Facebook);
CreateAndShowDialog(string.Format("you are now logged in - {0}", user.UserId), "Logged in!");
}
catch (Exception ex)
{
CreateAndShowDialog(ex, "Authentication failed");
}
}
This creates a new method to handle the authentication process. The user is authenticated by using a Facebook login. A dialog is displayed which displays the ID of the authenticated user.
> [AZURE.NOTE] If you are using an identity provider other than a Facebook, change the value passed to **LoginAsync** above to one of the following: _MicrosoftAccount_, _Twitter_, _Google_, or _WindowsAzureActiveDirectory_.
3. In the **OnCreate** method, add the following line of code after the code that instantiates the `MobileServiceClient` object.
await Authenticate(); // add this line
This call starts the authentication process and awaits it asynchronously.
4. From the **Run** menu, click **Start debugging** to start the app and sign in with your chosen identity provider.
When you are successfully logged-in, the app should run without errors, and you should be able to query Mobile Services and make updates to data.
[Register your app for authentication and configure Mobile Services]: #register
[Restrict table permissions to authenticated users]: #permissions
[Add authentication to the app]: #add-authentication
[Next Steps]:#next-steps
[Submit an app page]: http://go.microsoft.com/fwlink/p/?LinkID=266582
[My Applications]: http://go.microsoft.com/fwlink/p/?LinkId=262039
[Live SDK for Windows]: http://go.microsoft.com/fwlink/p/?LinkId=262253
[Get started with Mobile Services]: mobile-services-dotnet-backend-xamarin-android-get-started.md
[Get started with authentication]: mobile-services-dotnet-backend-xamarin-android-get-started-users.md
[Get started with push notifications]: mobile-services-dotnet-backend-xamarin-android-get-started-push.md
[Authorize users with scripts]: mobile-services-dotnet-backend-service-side-authorization.md
[JavaScript and HTML]: mobile-services-dotnet-backend-windows-store-javascript-get-started-users.md
================================================
FILE: docs/mobile-services-dotnet-backend-xamarin-android-get-started.md
================================================
# Get started with Mobile Services
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal JavaScript | Javascript)](mobile-services-javascript-backend-windows-store-javascript-get-started.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started.md)
- [(Android | Javascript)](mobile-services-android-get-started.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started.md)
- [(HTML | Javascript)](mobile-services-html-get-started.md)
- [(PhoneGap | Javascript)](mobile-services-javascript-backend-phonegap-get-started.md)
- [(Sencha | Javascript)](partner-sencha-mobile-services-get-started.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This tutorial shows you how to add a cloud-based backend service to a Xamarin Android app using Azure Mobile Services. In this tutorial, you will create both a new mobile service and a simple _To do list_ app that stores app data in the new mobile service. The mobile service that you will create uses the supported .NET languages using Visual Studio for server-side business logic and to manage the mobile service. To create a mobile service that lets you write your server-side business logic in JavaScript, see the [JavaScript backend version] of this topic.
>[AZURE.NOTE]This topic shows you how to create a new mobile service project by using the Azure classic portal. By using Visual Studio 2013 Update 2, you can also add a new mobile service project to an existing Visual Studio solution. For more information, see [Quickstart: Add a mobile service (.NET backend)](http://msdn.microsoft.com/library/windows/apps/dn629482.aspx)
A screenshot from the completed app is below:
![][0]
Completing this tutorial is a prerequisite for all other Mobile Services tutorials for Xamarin Android apps.
>[AZURE.NOTE]To complete this tutorial, you need an Azure account. If you don't have an account, you can sign up for an Azure trial and get up to 10 free mobile services that you can keep using even after your trial ends. For details, see [Azure Free Trial](https://azure.microsoft.com/pricing/free-trial/?WT.mc_id=A0E0E5C02&returnurl=http%3A%2F%2Fazure.microsoft.com%2Fen-us%2Fdocumentation%2Farticles%2Fmobile-services-dotnet-backend-xamarin-android-get-started).
>This tutorial requires [Visual Studio Professional 2013](https://go.microsoft.com/fwLink/p/?LinkID=257546). A free trial version is available.
## Create a new mobile service
Follow these steps to create a new mobile service.
1. Log into the [Azure classic portal](https://manage.windowsazure.com/). At the bottom of the navigation pane, click **+NEW**. Expand **Compute** and **Mobile Service**, then click **Create**.

This displays the **Create a Mobile Service** dialog.
2. In the **Create a Mobile Service** page, select **Create a free 20 MB SQL Database**, select **.NET** runtime, then type a subdomain name for the new mobile service in the **URL** textbox. Click the right arrow button to go to the next page.

This displays the **Specify database settings** page.
> [AZURE.NOTE] As part of this tutorial, you create a new SQL Database instance and server. You can reuse this new database and administer it as you would any other SQL Database instance. If you already have a database in the same region as the new mobile service, you can instead choose **Use existing Database** and then select that database. The use of a database in a different region is not recommended because of additional bandwidth costs and higher latencies.
3. In **Name**, type the name of the new database, then type **Login name**, which is the administrator login name for the new SQL Database server, type and confirm the password, and click the check button to complete the process.

You have now created a new mobile service that can be used by your mobile apps.
## Create a new Xamarin Android app
Once you have created your mobile service, you can follow an easy quickstart in the classic portal to either create a new app or modify an existing app to connect to your mobile service.
In this section you will download a new Xamarin Android app and a service project for your mobile service.
1. If you haven't already done so, install Visual Studio with Xamarin. Instructions can be found on [Setup and Install for Visual Studio and Xamarin](https://msdn.microsoft.com/library/mt613162.aspx). You can also use Xamarin Studio on a Mac OS X machine, see [Setup, install, and verifications for Mac users](https://msdn.microsoft.com/library/mt488770.aspx).
2. In the [classic portal], click **Mobile Services**, and then click the mobile service that you just created.
3. In the quickstart tab, click **Xamarin** under **Choose platform** and expand **Create a new Xamarin app**.
![][6]
This displays the three easy steps to create a Xamarin Android app connected to your mobile service.
![][7]
4. Under **Download and publish your service to the cloud**, select **Android** and click **Download**.
This downloads a solution containing projects for both the mobile service and for the sample _To do list_ application that is connected to your mobile service. Save the compressed project file to your local computer, and make a note of where you save it.
5. Download your publish profile, save the downloaded file to your local computer, and make a note of where you save it.
## Test the mobile service
The mobile service project lets you run your new mobile service locally. This makes it easy to debug your service code before you even publish it to Azure.
1. On your Windows PC, download your personalized server project, extract it, and then open it in Visual Studio.
2. Press the **F5** key to rebuild the project and start the mobile service locally. A web page is displayed after the mobile service starts successfully.
## Publish your mobile service
1. In Visual Studio, right-click the project, click **Publish** > **Microsoft Azure Mobile Services**. Instead of using Visual Studio, [you may also use Git](./
mobile-services-dotnet-backend-store-code-source-control.md).
2. Sign in with Azure credentials and select your service from **Existing Mobile Services**. Visual Studio downloads your publish settings directly from Azure. Finally, click **Publish**.
## Run the Xamarin Android app
The final stage of this tutorial is to build and run your new app.
1. Navigate to the client project within the mobile service solution, in either Visual Studio or Xamarin Studio.
2. Press the **Run** button to build the project and start the app. You will be asked to select an emulator or a connected USB device.
> [AZURE.NOTE] To be able to run the project in the Android emulator, you must define a least one Android Virtual Device (AVD). Use the AVD Manager to create and manage these devices.
3. In the app, type meaningful text, such as _Complete the tutorial_ and then click the plus (**+**) icon.
![][10]
This sends a POST request to the new mobile service hosted in Azure. Data from the request is inserted into the TodoItem table. Items stored in the table are returned by the mobile service, and the data is displayed in the list.
> [AZURE.NOTE]
> You can review the code that accesses your mobile service to query and insert data, which is found in the ToDoActivity.cs C# file.
## Next Steps
Now that you have completed the quickstart, learn how to perform additional important tasks in Mobile Services:
* [Get started with offline data sync]
Learn how the quickstart uses offline data sync to make the app responsive and robust.
* [Get started with authentication]
Learn how to authenticate users of your app with an identity provider.
* [Get started with push notifications]
Learn how to send a very basic push notification to your app.
* [Troubleshoot a Mobile Services .NET backend]
Learn how to diagnose and fix issues that can arise with a Mobile Services .NET backend.
[Getting started with Mobile Services]:#getting-started
[Create a new mobile service]:#create-new-service
[Next Steps]:#next-steps
[0]: ./media/mobile-services-dotnet-backend-xamarin-android-get-started/mobile-quickstart-completed-android.png
[6]: ./media/mobile-services-dotnet-backend-xamarin-android-get-started/mobile-portal-quickstart-xamarin.png
[7]: ./media/mobile-services-dotnet-backend-xamarin-android-get-started/mobile-quickstart-steps-xamarin-android.png
[8]: ./media/mobile-services-dotnet-backend-xamarin-android-get-started/mobile-xamarin-project-android-vs.png
[9]: ./media/mobile-services-dotnet-backend-xamarin-android-get-started/mobile-xamarin-project-android-xs.png
[10]: ./media/mobile-services-dotnet-backend-xamarin-android-get-started/mobile-quickstart-startup-android.png
[Get started with offline data sync]: mobile-services-xamarin-android-get-started-offline-data.md
[Get started with authentication]: mobile-services-dotnet-backend-xamarin-android-get-started-users.md
[Get started with push notifications]: mobile-services-dotnet-backend-xamarin-android-get-started-push.md
[Visual Studio Professional 2013]: https://go.microsoft.com/fwLink/p/?LinkID=257546
[Mobile Services SDK]: http://go.microsoft.com/fwlink/?LinkId=257545
[JavaScript and HTML]: mobile-services-win8-javascript/
[Azure classic portal]: https://manage.windowsazure.com/
[classic portal]: https://manage.windowsazure.com/
[JavaScript backend version]: mobile-services-android-get-started.md
[Troubleshoot a Mobile Services .NET backend]: mobile-services-dotnet-backend-how-to-troubleshoot.md
================================================
FILE: docs/mobile-services-dotnet-backend-xamarin-ios-get-started-users.md
================================================
# Add authentication to your Mobile Services app
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-users.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started-users.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-users.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-get-started-users.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-windows-phone-get-started-users.md)
- [(Android | Javascript)](mobile-services-android-get-started-users.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started-users.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-users.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-users.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-users.md)
- [(HTML | Javascript)](mobile-services-html-get-started-users.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This topic shows you how to authenticate users in Mobile Services from your app. In this tutorial, you add authentication to the quickstart project using an identity provider that is supported by Mobile Services. After being successfully authenticated and authorized by Mobile Services, the user ID value is displayed.
This tutorial walks you through these basic steps to enable authentication in your app:
1. [Register your app for authentication and configure Mobile Services]
2. [Restrict table permissions to authenticated users]
3. [Add authentication to the app]
This tutorial is based on the Mobile Services quickstart. You must also first complete the tutorial [Get started with Mobile Services].
## Register your app for authentication and configure Mobile Services
1. In the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Dashboard**, and make a note of the **Mobile Service URL** value.
2. Register your app with one or more of the following authentication providers:
* [Google](./
mobile-services-how-to-register-google-authentication.md)
* [Facebook](./
mobile-services-how-to-register-facebook-authentication.md)
* [Twitter](./
mobile-services-how-to-register-twitter-authentication.md)
* [Microsoft](./
mobile-services-how-to-register-microsoft-authentication.md)
* [Azure Active Directory](./
mobile-services-how-to-register-active-directory-authentication.md).
Make a note of the client identity and client secret values generated by the provider. Do not distribute or share the client secret.
3. Back in the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Identity** > your identity provider settings, then enter the client ID and secret value from your provider.
You've now configured both your app and your mobile service to work with your auth provider. You may optionally repeat all these steps for each additional identity provider you'd like to support.
> [AZURE.IMPORTANT] Verify that you've set the correct redirect URI on your identity provider's developer site. As described in the linked instructions for each provider above, the redirect URI may be different for a .NET backend service vs. for a JavaScript backend service. An incorrectly configured redirect URI may result in the login screen not being displayed properly and the app malfunctioning in unexpected ways.
### (Optional) Configure your .NET Mobile Service for Azure Active Directory
>[AZURE.NOTE] These steps are optional because they only apply to the Azure Active Directory login provider.
1. Install the [WindowsAzure.MobileServices.Backend.Security NuGet package](https://www.nuget.org/packages/WindowsAzure.MobileServices.Backend.Security).
2. In Visual Studio expand App_Start and open WebApiConfig.cs. Add the following `using` statement at the top:
using Microsoft.WindowsAzure.Mobile.Service.Security.Providers;
3. Also in WebApiConfig.cs, add the following code to the `Register` method, immediately after `options` is instantiated:
options.LoginProviders.Remove(typeof(AzureActiveDirectoryLoginProvider));
options.LoginProviders.Add(typeof(AzureActiveDirectoryExtendedLoginProvider));
## Restrict permissions to authenticated users
By default, all requests to mobile service resources are restricted to clients that present the application key, which does not strictly secure access to resources. To secure your resources, you must restrict access to only authenticated clients.
1. In Visual Studio, open your mobile service project, expand the Controllers folder, and open **TodoItemController.cs**. The **TodoItemController** class implements data access for the TodoItem table. Add the following `using` statement:
using Microsoft.WindowsAzure.Mobile.Service.Security;
2. Apply the following _AuthorizeLevel_ attribute to the **TodoItemController** class.
[AuthorizeLevel(AuthorizationLevel.User)]
This makes sure that all operations against the _TodoItem_ table require an authenticated user. You can also apply the *AuthorizeLevel* attribute at the method level.
3. (Optional) If you wish to debug authentication locally, expand the `App_Start` folder, open **WebApiConfig.cs**, and add the following code to the **Register** method.
config.SetIsHosted(true);
This tells the local mobile service project to run as if it is being hosted in Azure, including honoring the *AuthorizeLevel* settings. Without this setting, all HTTP requests to localhost are permitted without authentication despite the *AuthorizeLevel* setting. When you enable self-hosted mode, you also need to set a value for the local application key.
4. (Optional) In the web.config project file, set a string value for the `MS_ApplicationKey` app setting.
This is the password that you use (with no username) to test the API help pages when you run the service locally. This string value is not used by the live site in Azure, and you do not need to use the actual application key; any valid string value will work.
4. Republish your project.
6. In Visual Studio or Xamarin Studio, run the client project on a device or simulator. Verify that an unhandled exception with a status code of 401 (Unauthorized) is raised after the app starts.
This happens because the app attempts to access Mobile Services as an unauthenticated user, but the *TodoItem* table now requires authentication.
Next, you will update the app to authenticate users before requesting resources from the mobile service.
## Add authentication to the app
In this section, you will modify the app to display a login screen before displaying data. When the app starts, it will not connect to your mobile service and will not display any data. After the first time that the user performs the refresh gesture, the login screen will appear; after successful login the list of todo items will be displayed.
1. In the client project, open the file **QSTodoService.cs** and add the following declarations to QSTodoService:
// Mobile Service logged in user
private MobileServiceUser user;
public MobileServiceUser User { get { return user; } }
2. Add a new method **Authenticate** to **QSTodoService** with the following definition:
private async Task Authenticate(UIViewController view)
{
try
{
user = await client.LoginAsync(view, MobileServiceAuthenticationProvider.Facebook);
}
catch (Exception ex)
{
Console.Error.WriteLine (@"ERROR - AUTHENTICATION FAILED {0}", ex.Message);
}
}
> [AZURE.NOTE] When you use an identity provider other than a Facebook, change the value passed to **LoginAsync** above to one of the following: _MicrosoftAccount_, _Twitter_, _Google_, or _WindowsAzureActiveDirectory_.
3. Open **QSTodoListViewController.cs** and modify the method definition of **ViewDidLoad** to remove or comment-out the call to **RefreshAsync()** near the end.
4. Add the following code at the top of the **RefreshAsync** method definition:
// Add at the start of the RefreshAsync method.
if (todoService.User == null) {
await QSTodoService.DefaultService.Authenticate (this);
if (todoService.User == null) {
Console.WriteLine ("You must sign in.");
return;
}
}
This displays a sign-in screen to attempt authentication when the **User** property is null. When the login is successful the **User** is set.
5. Press the **Run** button to build the project and start the app in the iPhone simulator. Verify that the app displays no data. **RefreshAsync()** has not yet been called.
6. Perform the refresh gesture by pulling down the list of items, which calls **RefreshAsync()**. This calls **Authenticate()** to start authentication and the login screen is displayed. After you have successfully authenticated, the app displays the list of todo items and you can make updates to the data.
## Next steps
In the next tutorial, [Service-side authorization of Mobile Services users][Authorize users with scripts], you will take the user ID value provided by Mobile Services based on an authenticated user and use it to filter the data returned by Mobile Services.
[Register your app for authentication and configure Mobile Services]: #register
[Restrict table permissions to authenticated users]: #permissions
[Add authentication to the app]: #add-authentication
[Next Steps]:#next-steps
[Submit an app page]: http://go.microsoft.com/fwlink/p/?LinkID=266582
[My Applications]: http://go.microsoft.com/fwlink/p/?LinkId=262039
[Live SDK for Windows]: http://go.microsoft.com/fwlink/p/?LinkId=262253
[Get started with Mobile Services]: mobile-services-dotnet-backend-xamarin-ios-get-started.md
[Get started with authentication]: mobile-services-dotnet-backend-xamarin-ios-get-started-users.md
[Get started with push notifications]: mobile-services-dotnet-backend-xamarin-ios-get-started-push.md
[Authorize users with scripts]: mobile-services-dotnet-backend-service-side-authorization.md
[JavaScript and HTML]: mobile-services-dotnet-backend-windows-store-javascript-get-started-users.md
================================================
FILE: docs/mobile-services-dotnet-backend-xamarin-ios-get-started.md
================================================
# Get started with Mobile Services
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal JavaScript | Javascript)](mobile-services-javascript-backend-windows-store-javascript-get-started.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started.md)
- [(Android | Javascript)](mobile-services-android-get-started.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started.md)
- [(HTML | Javascript)](mobile-services-html-get-started.md)
- [(PhoneGap | Javascript)](mobile-services-javascript-backend-phonegap-get-started.md)
- [(Sencha | Javascript)](partner-sencha-mobile-services-get-started.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This tutorial shows you how to add a cloud-based backend service to a Xamarin iOS app using Azure Mobile Services. In this tutorial, you will create both a new mobile service and a simple _To do list_ app that stores app data in the new mobile service. The mobile service that you will create uses the supported .NET languages using Visual Studio for server-side business logic and to manage the mobile service. To create a mobile service that lets you write your server-side business logic in JavaScript, see the [JavaScript backend version] of this topic.
>[AZURE.NOTE]This topic shows you how to create a new mobile service project by using the Azure classic portal. By using Visual Studio 2013 Update 2, you can also add a new mobile service project to an existing Visual Studio solution. For more information, see [Quickstart: Add a mobile service (.NET backend)](http://msdn.microsoft.com/library/windows/apps/dn629482.aspx)
A screenshot from the completed app is below:
![][0]
Completing this tutorial is a prerequisite for all other Mobile Services tutorials for Xamarin iOS apps.
>[AZURE.NOTE]To complete this tutorial, you need an Azure account. If you don't have an account, you can sign up for an Azure trial and get up to 10 free mobile services that you can keep using even after your trial ends. For details, see Azure Free Trial. This tutorial requires Visual Studio Professional 2013. A free trial version is available.
## Create a new mobile service
Follow these steps to create a new mobile service.
1. Log into the [Azure classic portal](https://manage.windowsazure.com/). At the bottom of the navigation pane, click **+NEW**. Expand **Compute** and **Mobile Service**, then click **Create**.

This displays the **Create a Mobile Service** dialog.
2. In the **Create a Mobile Service** page, select **Create a free 20 MB SQL Database**, select **.NET** runtime, then type a subdomain name for the new mobile service in the **URL** textbox. Click the right arrow button to go to the next page.

This displays the **Specify database settings** page.
> [AZURE.NOTE] As part of this tutorial, you create a new SQL Database instance and server. You can reuse this new database and administer it as you would any other SQL Database instance. If you already have a database in the same region as the new mobile service, you can instead choose **Use existing Database** and then select that database. The use of a database in a different region is not recommended because of additional bandwidth costs and higher latencies.
3. In **Name**, type the name of the new database, then type **Login name**, which is the administrator login name for the new SQL Database server, type and confirm the password, and click the check button to complete the process.

You have now created a new mobile service that can be used by your mobile apps.
## Create a new Xamarin iOS app
Once you have created your mobile service, you can follow an easy quickstart in the Azure classic portal to either create a new app or modify an existing app to connect to your mobile service.
In this section you will download a new Xamarin iOS app and a service project for your mobile service.
1. If you haven't already done so, install Visual Studio with Xamarin. Instructions can be found on [Setup and Install for Visual Studio and Xamarin](https://msdn.microsoft.com/library/mt613162.aspx). You can also use Xamarin Studio on a Mac OS X machine, see [Setup, install, and verifications for Mac users](https://msdn.microsoft.com/library/mt488770.aspx).
2. In the [Azure classic portal], click **Mobile Services**, and then click the mobile service that you just created.
3. In the quickstart tab, click **Xamarin** under **Choose platform** and expand **Create a new Xamarin app**.
![][6]
This displays the three easy steps to create a Xamarin iOS app connected to your mobile service.
![][7]
4. Under **Download and publish your service to the cloud**, select **iOS** and click **Download**.
This downloads a solution contains projects for both the mobile service and for the sample _To do list_ application that is connected to your mobile service. Save the compressed project file to your local computer, and make a note of where you save it.
5. Download your publish profile, save the downloaded file to your local computer, and make a note of where you save it.
## Test the mobile service
The mobile service project lets you run your new mobile service locally. This makes it easy to debug your service code before you even publish it to Azure.
1. On your Windows PC, download your personalized server project, extract it, and then open it in Visual Studio.
2. Press the **F5** key to rebuild the project and start the mobile service locally. A web page is displayed after the mobile service starts successfully.
## Publish your mobile service
1. In Visual Studio, right-click the project, click **Publish** > **Microsoft Azure Mobile Services**. Instead of using Visual Studio, [you may also use Git](./
mobile-services-dotnet-backend-store-code-source-control.md).
2. Sign in with Azure credentials and select your service from **Existing Mobile Services**. Visual Studio downloads your publish settings directly from Azure. Finally, click **Publish**.
## Run the Xamarin iOS app
The final stage of this tutorial is to build and run your new app.
1. Navigate to the client project within the mobile service solution, in either Visual Studio or Xamarin Studio.
![][8]
![][9]
2. Press the **Run** button to build the client project and start the app in the iPhone emulator.
3. In the app, type meaningful text, such as _Complete the tutorial_ and then click the plus (**+**) icon.
![][10]
This sends a POST request to the new mobile service hosted in Azure. Data from the request is inserted into the TodoItem table. Items stored in the table are returned by the mobile service, and the data is displayed in the list.
>[AZURE.NOTE]You can review the code that accesses your mobile service to query and insert data in the QSTodoService.cs C# file.
## Next Steps
Now that you have completed the quickstart, learn how to perform additional important tasks in Mobile Services:
* [Get started with offline data sync]
Learn how the quickstart uses offline data sync to make the app responsive and robust.
* [Get started with authentication]
Learn how to authenticate users of your app with an identity provider.
* [Get started with push notifications]
Learn how to send a very basic push notification to your app.
* [Troubleshoot a Mobile Services .NET backend]
Learn how to diagnose and fix issues that can arise with a Mobile Services .NET backend.
[Getting started with Mobile Services]:#getting-started
[Create a new mobile service]:#create-new-service
[Next Steps]:#next-steps
[0]: ./media/mobile-services-dotnet-backend-xamarin-ios-get-started/mobile-quickstart-completed-ios.png
[6]: ./media/mobile-services-dotnet-backend-xamarin-ios-get-started/mobile-portal-quickstart-xamarin-ios.png
[7]: ./media/mobile-services-dotnet-backend-xamarin-ios-get-started/mobile-quickstart-steps-xamarin-ios.png
[8]: ./media/mobile-services-dotnet-backend-xamarin-ios-get-started/mobile-xamarin-project-ios-vs.png
[9]: ./media/mobile-services-dotnet-backend-xamarin-ios-get-started/mobile-xamarin-project-ios-xs.png
[10]: ./media/mobile-services-dotnet-backend-xamarin-ios-get-started/mobile-quickstart-startup-ios.png
[Get started with offline data sync]: mobile-services-xamarin-ios-get-started-offline-data.md
[Get started with authentication]: mobile-services-dotnet-backend-xamarin-ios-get-started-users.md
[Get started with push notifications]: mobile-services-dotnet-backend-xamarin-ios-get-started-push.md
[Visual Studio Professional 2013]: https://go.microsoft.com/fwLink/p/?LinkID=257546
[Mobile Services SDK]: http://go.microsoft.com/fwlink/?LinkId=257545
[JavaScript and HTML]: mobile-services-win8-javascript/
[Azure classic portal]: https://manage.windowsazure.com/
[JavaScript backend version]: mobile-services-ios-get-started.md
[Troubleshoot a Mobile Services .NET backend]: mobile-services-dotnet-backend-how-to-troubleshoot.md
================================================
FILE: docs/mobile-services-dotnet-how-to-use-client-library.md
================================================
# How to use the managed client library for Azure Mobile Services
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
> [AZURE.SELECTOR]
- [Android](mobile-services-android-how-to-use-client-library.md)
- [HTML/JavaScript](mobile-services-html-how-to-use-client-library.md)
- [iOS](mobile-services-ios-how-to-use-client-library.md)
- [Managed (Windows/Xamarin)](mobile-services-dotnet-how-to-use-client-library.md)
## Overview
This guide shows you how to perform common scenarios using the managed client library for Azure Mobile Services in Windows and Xamarin apps. The scenarios covered include querying for data, inserting, updating, and deleting data, authenticating users, and handling errors. If you are new to Mobile Services, you should consider first completing the [Mobile Services quickstart](mobile-services-dotnet-backend-xamarin-ios-get-started.md) tutorial.
## What is Mobile Services
Azure Mobile Services is a highly scalable mobile application development platform that lets you add enhanced functionality to your mobile device apps by using Azure.
With Mobile Services you can:
+ **Build native and cross platform apps** - Connect your iOS, Android, Windows, or cross-platform Xamarin or Cordova (Phonegap) apps to your backend mobile service using native SDKs.
+ **Send push notifications to your users** - Send push notifications to your users of your app.
+ **Authenticate your users** - Leverage popular identity providers like Facebook and Twitter to authenticate your app users.
+ **Store data in the cloud** - Store user data in a SQL Database (by default) or in Mongo DB, DocumentDB, Azure Tables, or Azure Blobs.
+ **Build offline-ready apps with sync** - Make your apps work offline and use Mobile Services to sync data in the background.
+ **Monitor and scale your apps** - Monitor app usage and scale your backend as demand grows.
## Mobile Services Concepts
The following are important features and concepts in the Mobile Services:
+ **Application key:** a unique value that is used to limit access to your mobile service from random clients; this "key" is not a security token and is not used to authenticate users of your app.
+ **Backend:** the mobile service instance that supports your app. A mobile service is implemented either as an ASP.NET Web API project (*.NET backend* ) or as a Node.js project (*JavaScript backend*).
+ **Identity provider:** an external service, trusted by Mobile Services, that authenticates your app's users. Supported providers include: Facebook, Twitter, Google, Microsoft Account, and Azure Active Directory.
+ **Push notification:** Service-initiated message that is sent to a registered device or user using Azure Notification Hubs.
+ **Scale:** The ability to add, for an additional cost, more processing power, performance, and storage as your app becomes more popular.
+ **Scheduled job:** Custom code that is run either on a pre-determined schedule or on-demand.
For more information, see [Mobile Services Concepts](./
mobile-services-concepts-links.md).
## Setup and Prerequisites
We assume that you have created a mobile service and a table. For more information see [Create a table](http://go.microsoft.com/fwlink/?LinkId=298592). In the code used in this topic, the table is named `TodoItem` and it will have the following columns: `Id`, `Text`, and `Complete`.
The corresponding typed client-side .NET type is the following:
public class TodoItem
{
public string Id { get; set; }
[JsonProperty(PropertyName = "text")]
public string Text { get; set; }
[JsonProperty(PropertyName = "complete")]
public bool Complete { get; set; }
}
Note that the [JsonPropertyAttribute](http://www.newtonsoft.com/json/help/html/Properties_T_Newtonsoft_Json_JsonPropertyAttribute.htm) is used to define the mapping between the PropertyName mapping between the client type and the table.
When dynamic schema is enabled in a JavaScript backend mobile service, Azure Mobile Services automatically generates new columns based on the object in insert or update requests. For more information, see [Dynamic schema](http://go.microsoft.com/fwlink/?LinkId=296271). In a .NET backend mobile service, the table is defined in the data model of the project.
## How to: Create the Mobile Services client
The following code creates the `MobileServiceClient` object that is used to access your mobile service.
MobileServiceClient client = new MobileServiceClient(
"AppUrl",
"AppKey"
);
In the code above, replace `AppUrl` and `AppKey` with the mobile service URL and application key, in that order. Both of these are available on the Azure classic portal, by selecting your mobile service and then clicking on "Dashboard".
>[AZURE.IMPORTANT]The application key is intended to filter-out random request against your mobile service, and it is distributed with the application. Because this key is not encrypted, it cannot be considered secure. To truly secure your mobile service data, you must instead authenticate users before allowing access. For more information, see [How to: Authenticate users](#authentication).
## How to: Create a table reference
All of the code that accesses or modifies data in the Mobile Services table calls functions on the `MobileServiceTable` object. You get a reference to the table by calling the [GetTable](https://msdn.microsoft.com/library/azure/jj554275.aspx) method on an instance of the `MobileServiceClient`, as follows:
IMobileServiceTable todoTable =
client.GetTable();
This is the typed serialization model; see the discussion of the [untyped serialization model](#untyped) below.
## How to: Query data from a mobile service
This section describes how to issue queries to the mobile service, which includes the following functionality:
- [Filter returned data]
- [Sort returned data]
- [Return data in pages]
- [Select specific columns]
- [Look up data by ID]
>[AZURE.NOTE] A server-driven page size is enforced to prevent all rows from being returned. This keeps default requests for large data sets from negatively impacting the service. To return more than 50 rows, use the `Take` method, as described in [Return data in pages].
### How to: Filter returned data
The following code illustrates how to filter data by including a `Where` clause in a query. It returns all items from `todoTable` whose `Complete` property is equal to `false`. The `Where` function applies a row filtering predicate to the query against the table.
// This query filters out completed TodoItems and
// items without a timestamp.
List items = await todoTable
.Where(todoItem => todoItem.Complete == false)
.ToListAsync();
You can view the URI of the request sent to the mobile service by using message inspection software, such as browser developer tools or [Fiddler]. If you look at the request URI below, notice that we are modifying the query string itself:
GET /tables/todoitem?$filter=(complete+eq+false) HTTP/1.1
This request would normally be translated roughly into the following SQL query on the server side:
SELECT *
FROM TodoItem
WHERE ISNULL(complete, 0) = 0
The function which is passed to the `Where` method can have an arbitrary number of conditions. For example, the line below:
// This query filters out completed TodoItems where Text isn't null
List items = await todoTable
.Where(todoItem => todoItem.Complete == false
&& todoItem.Text != null)
.ToListAsync();
Would be roughly translated (for the same request shown before) as
SELECT *
FROM TodoItem
WHERE ISNULL(complete, 0) = 0
AND ISNULL(text, 0) = 0
The `where` statement above will find items with `Complete` status set to false with non-null `Text`.
We also could have written that in multiple lines instead:
List items = await todoTable
.Where(todoItem => todoItem.Complete == false)
.Where(todoItem => todoItem.Text != null)
.ToListAsync();
The two methods are equivalent and may be used interchangeably. The former option -- of concatenating multiple predicates in one query -- is more compact and recommended.
The `where` clause supports operations that be translated into the Mobile Services OData subset. This includes relational operators (==, !=, <, <=, >, >=), arithmetic operators (+, -, /, *, %), number precision (Math.Floor, Math.Ceiling), string functions (Length, Substring, Replace, IndexOf, StartsWith, EndsWith), date properties (Year, Month, Day, Hour, Minute, Second), access properties of an object, and expressions combining all of these.
### How to: Sort returned data
The following code illustrates how to sort data by including an `OrderBy` or `OrderByDescending` function in the query. It returns items from `todoTable` sorted ascending by the `Text` field.
// Sort items in ascending order by Text field
MobileServiceTableQuery query = todoTable
.OrderBy(todoItem => todoItem.Text)
List items = await query.ToListAsync();
// Sort items in descending order by Text field
MobileServiceTableQuery query = todoTable
.OrderByDescending(todoItem => todoItem.Text)
List items = await query.ToListAsync();
### How to: Return data in pages
By default, the server returns only the first 50 rows. You can increase the number of returned rows by calling the [Take] method. Use `Take` along with the [Skip] method to request a specific "page" of the total dataset returned by the query. The following query, when executed, returns the top three items in the table.
// Define a filtered query that returns the top 3 items.
MobileServiceTableQuery query = todoTable
.Take(3);
List items = await query.ToListAsync();
The following revised query skips the first three results and returns the next three after that. This is effectively the second "page" of data, where the page size is three items.
// Define a filtered query that skips the top 3 items and returns the next 3 items.
MobileServiceTableQuery query = todoTable
.Skip(3)
.Take(3);
List items = await query.ToListAsync();
You can also use the [IncludeTotalCount] method to ensure that the query will get the total count for all the records that would have been returned, ignoring any take paging/limit clause specified:
query = query.IncludeTotalCount();
This is a simplified scenario of passing hard-coded paging values to the `Take` and `Skip` methods. In a real-world app, you can use queries similar to the above with a pager control or comparable UI to let users navigate to previous and next pages.
#### Paging considerations for a .NET backend mobile service
To override the 50 row limit in a .NET backend mobile service, you must also apply the [EnableQueryAttribute](https://msdn.microsoft.com/library/system.web.http.odata.enablequeryattribute.aspx) to the public GET method and specify the paging behavior. When applied to the method, the following sets the maximum returned rows to 1000:
[EnableQuery(MaxTop=1000)]
### How to: Select specific columns
You can specify which set of properties to include in the results by adding a `Select` clause to your query. For example, the following code shows how to select just one field and also how to select and format multiple fields:
// Select one field -- just the Text
MobileServiceTableQuery query = todoTable
.Select(todoItem => todoItem.Text);
List items = await query.ToListAsync();
// Select multiple fields -- both Complete and Text info
MobileServiceTableQuery query = todoTable
.Select(todoItem => string.Format("{0} -- {1}", todoItem.Text.PadRight(30), todoItem.Complete ? "Now complete!" : "Incomplete!"));
List items = await query.ToListAsync();
All the functions described so far are additive, so we can just keep calling them and we'll each time affect more of the query. One more example:
MobileServiceTableQuery query = todoTable
.Where(todoItem => todoItem.Complete == false)
.Select(todoItem => todoItem.Text)
.Skip(3).
.Take(3);
List items = await query.ToListAsync();
### How to: Look up data by ID
The `LookupAsync` function can be used to look up objects from the database with a particular ID.
// This query filters out the item with the ID of 37BBF396-11F0-4B39-85C8-B319C729AF6D
TodoItem item = await todoTable.LookupAsync("37BBF396-11F0-4B39-85C8-B319C729AF6D");
## How to: Insert data into a mobile service
> [AZURE.NOTE] If you want to perform insert, lookup, delete, or update operations on a type, then you need to create a member called **Id**. This is why the example class **TodoItem** has a member of name **Id**. A valid id value must always be present in update and delete operations.
The following code illustrates how to insert new rows into a table. The parameter contains the data to be inserted as a .NET object.
await todoTable.InsertAsync(todoItem);
If a unique custom ID value is not included in the `todoItem` passed to the `todoTable.InsertAsync` call, a value for ID is generated by the server and is set in the `todoItem` object returned to the client.
To insert untyped data, you may take advantage of Json.NET as shown below.
JObject jo = new JObject();
jo.Add("Text", "Hello World");
jo.Add("Complete", false);
var inserted = await table.InsertAsync(jo);
Here is an example using an email address as a unique string id.
JObject jo = new JObject();
jo.Add("id", "myemail@emaildomain.com");
jo.Add("Text", "Hello World");
jo.Add("Complete", false);
var inserted = await table.InsertAsync(jo);
### Working with ID values
Mobile Services supports unique custom string values for the table's **id** column. This allows applications to use custom values such as email addresses or user names for the ID.
String IDs provide you with the following benefits:
+ IDs are generated without making a round-trip to the database.
+ Records are easier to merge from different tables or databases.
+ IDs values can integrate better with an application's logic.
When a string ID value is not set on an inserted record, Mobile Services generates a unique value for the ID. You can use the `Guid.NewGuid()` method To generate your own ID values, either on the client or in a .NET mobile backend service. To learn more about generating GUIDs in a JavaScript backend mobile service, see [How to: Generate unique ID values](mobile-services-how-to-use-server-scripts.md#generate-guids).
You can also use integer IDs for your tables. To use an integer ID, you must create your table with the `mobile table create` command using the `--integerId` option. This command is used with the Command-line Interface (CLI) for Azure. For more information on using the CLI, see [CLI to manage Mobile Services tables](https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-command-line-tools/#Mobile_Tables).
## How to: Modify data in a mobile service
The following code illustrates how to update an existing instance with the same ID with new information. The parameter contains the data to be updated as a .NET object.
await todoTable.UpdateAsync(todoItem);
To insert untyped data, you may take advantage of Json.NET like so. Note that when making an update, an ID must be specified, as that is how the mobile service identifies which instance to update. The ID can be obtained from the result of the `InsertAsync` call.
JObject jo = new JObject();
jo.Add("Id", "37BBF396-11F0-4B39-85C8-B319C729AF6D");
jo.Add("Text", "Hello World");
jo.Add("Complete", false);
var inserted = await table.UpdateAsync(jo);
If you attempt to update an item without providing the "Id" value, there is no way for the service to tell which instance to update, so the Mobile Services SDK will throw an `ArgumentException`.
## How to: Delete data in a mobile service
The following code illustrates how to delete an existing instance. The instance is identified by the "Id" field set on the `todoItem`.
await todoTable.DeleteAsync(todoItem);
To delete untyped data, you may take advantage of Json.NET like so. Note that when making a delete request, an ID must be specified, as that is how the mobile service identifies which instance to delete. A delete request needs only the ID; other properties are not passed to the service, and if any are passed, they are ignored at the service. The result of a `DeleteAsync` call is usually `null` as well. The ID to pass in can be obtained from the result of the `InsertAsync` call.
JObject jo = new JObject();
jo.Add("Id", "37BBF396-11F0-4B39-85C8-B319C729AF6D");
await table.DeleteAsync(jo);
If you attempt to delete an item without the "Id" field already set, there is no way for the service to tell which instance to delete, so you will get back a `MobileServiceInvalidOperationException` from the service. Similarly, if you attempt to delete an untyped item without the "Id" field already set, you will again get back a `MobileServiceInvalidOperationException` from the service.
## How to: Call a custom API
A custom API enables you to define custom endpoints that expose server functionality that does not map to an insert, update, delete, or read operation. By using a custom API, you can have more control over messaging, including reading and setting HTTP message headers and defining a message body format other than JSON. For an example of how to create a custom API in your mobile service, see [How to: define a custom API endpoint](mobile-services-dotnet-backend-define-custom-api.md).
You call a custom API by calling one of the [InvokeApiAsync] method overloads on the client. For example, the following line of code sends a POST request to the **completeAll** API on the mobile service:
var result = await App.MobileService
.InvokeApiAsync("completeAll",
System.Net.Http.HttpMethod.Post, null);
Note that this a typed method call, which requires that the **MarkAllResult** return type be defined. Both typed and untyped methods are supported. This is an almost trivial example as it is typed, sends no payload, has no query parameters, and doesn't change the request headers. For more realistic examples and a more a complete discussion of [InvokeApiAsync], see [Custom API in Azure Mobile Services Client SDKs].
## How to: Register for push notifications
The Mobile Services client enables you to register for push notifications with Azure Notification Hubs. When registering, you obtain a handle that you obtain from the platform-specific Push Notification Service (PNS). You then provide this value along with any tags when you create the registration. The following code registers your Windows app for push notifications with the Windows Notification Service (WNS):
private async void InitNotificationsAsync()
{
// Request a push notification channel.
var channel =
await PushNotificationChannelManager
.CreatePushNotificationChannelForApplicationAsync();
// Register for notifications using the new channel and a tag collection.
var tags = new List{ "mytag1", "mytag2"};
await MobileService.GetPush().RegisterNativeAsync(channel.Uri, tags);
}
Note that in this example, two tags are included with the registration. For more information on Windows apps, see [Add push notifications to your app](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-push.md).
Xamarin apps require some additional code to be able to register a Xamarin app running on iOS or Android app with the Apple Push Notification Service (APNS) and Google Cloud Messaging (GCM) services, respectively. For more information see **Add push notifications to your app** ([Xamarin.iOS](partner-xamarin-mobile-services-ios-get-started-push.md#add-push) | [Xamarin.Android](partner-xamarin-mobile-services-android-get-started-push.md#add-push)).
>[AZURE.NOTE]When you need to send notifications to specific registered users, it is important to require authentication before registration, and then verify that the user is authorized to register with a specific tag. For example, you must check to make sure a user doesn't register with a tag that is someone else's user ID. For more information, see [Send push notifications to authenticated users](mobile-services-dotnet-backend-windows-store-dotnet-push-notifications-app-users.md).
## How to: Use periodic notifications in a Windows app
Windows supports period notifications (pull notifications) to update live tiles. With periodic notifications enabled, Windows will periodically access a custom API endpoint to update the app tile on the start menu. To use periodic notifications, you must [define a custom API](mobile-services-javascript-backend-define-custom-api.md) that returns XML data in a tile-specific format. For more information, see [Periodic notifications](https://msdn.microsoft.com/library/windows/apps/hh761461.aspx).
The following example turns on period notifications to request tile template data from a *tiles* custom endpoint:
TileUpdateManager.CreateTileUpdaterForApplication().StartPeriodicUpdate(
new System.Uri(MobileService.ApplicationUri, "/api/tiles"),
PeriodicUpdateRecurrence.Hour
);
Select a [PeriodicUpdateRecurrance](https://msdn.microsoft.com/library/windows/apps/windows.ui.notifications.periodicupdaterecurrence.aspx) value that best matches the update frequency of your data.
## How to: Use optimistic concurrency
Two or more clients may write changes to the same item, at the same time, in some scenarios. Without any conflict detection, the last write would overwrite any previous updates even if this was not the desired result. Optimistic Concurrency Control assumes that each transaction can commit and therefore does not use any resource locking. Before committing a transaction, optimistic concurrency control verifies that no other transaction has modified the data. If the data has been modified, the committing transaction is rolled back.
Mobile Services supports optimistic concurrency control by tracking changes to each item using the `__version` system property column that is defined for each table created by Mobile Services. Each time a record is updated, Mobile Services sets the `__version` property for that record to a new value. During each update request, the `__version` property of the record included with the request is compared to the same property for the record on the server. If the version passed with the request does not match the server, then the Mobile Services .NET client library throws a `MobileServicePreconditionFailedException`. The type included with the exception is the record from the server containing the server's version of the record. The application can then use this information to decide whether to execute the update request again with the correct `__version` value from the server to commit changes.
To enable optimistic concurrency the application defines a column on the table class for the `__version` system property. The following definition provides an example.
public class TodoItem
{
public string Id { get; set; }
[JsonProperty(PropertyName = "text")]
public string Text { get; set; }
[JsonProperty(PropertyName = "complete")]
public bool Complete { get; set; }
// *** Enable Optimistic Concurrency *** //
[JsonProperty(PropertyName = "__version")]
public byte[] Version { set; get; }
}
Applications using untyped tables enable optimistic concurrency by setting the `Version` flag on the `SystemProperties` of the table as follows.
//Enable optimistic concurrency by retrieving __version
todoTable.SystemProperties |= MobileServiceSystemProperties.Version;
The following code shows how to resolve a write conflict once detected. The correct `__version` value must be included in the `UpdateAsync()` call to commit a resolution.
private async void UpdateToDoItem(TodoItem item)
{
MobileServicePreconditionFailedException exception = null;
try
{
//update at the remote table
await todoTable.UpdateAsync(item);
}
catch (MobileServicePreconditionFailedException writeException)
{
exception = writeException;
}
if (exception != null)
{
// Conflict detected, the item has changed since the last query
// Resolve the conflict between the local and server item
await ResolveConflict(item, exception.Item);
}
}
private async Task ResolveConflict(TodoItem localItem, TodoItem serverItem)
{
//Ask user to choose the resoltion between versions
MessageDialog msgDialog = new MessageDialog(String.Format("Server Text: \"{0}\" \nLocal Text: \"{1}\"\n",
serverItem.Text, localItem.Text),
"CONFLICT DETECTED - Select a resolution:");
UICommand localBtn = new UICommand("Commit Local Text");
UICommand ServerBtn = new UICommand("Leave Server Text");
msgDialog.Commands.Add(localBtn);
msgDialog.Commands.Add(ServerBtn);
localBtn.Invoked = async (IUICommand command) =>
{
// To resolve the conflict, update the version of the
// item being committed. Otherwise, you will keep
// catching a MobileServicePreConditionFailedException.
localItem.Version = serverItem.Version;
// Updating recursively here just in case another
// change happened while the user was making a decision
UpdateToDoItem(localItem);
};
ServerBtn.Invoked = async (IUICommand command) =>
{
RefreshTodoItems();
};
await msgDialog.ShowAsync();
}
For a more complete example of using optimistic concurrency for Mobile Services, see the [Optimistic Concurrency Tutorial].
## How to: Bind mobile service data to a Windows user interface
This section shows how to display returned data objects using UI elements in a Windows app. To query incomplete items in `todoTable` and display it in a very simple list, you can run the following example code to bind the source of the list with a query. Using `MobileServiceCollection` creates a mobile services-aware binding collection.
// This query filters out completed TodoItems.
MobileServiceCollection items = await todoTable
.Where(todoItem => todoItem.Complete == false)
.ToCollectionAsync();
// itemsControl is an IEnumerable that could be bound to a UI list control
IEnumerable itemsControl = items;
// Bind this to a ListBox
ListBox lb = new ListBox();
lb.ItemsSource = items;
Some controls in the managed runtime support an interface called [ISupportIncrementalLoading](http://msdn.microsoft.com/library/windows/apps/Hh701916). This interface allows controls to request extra data when the user scrolls. There is built-in support for this interface for universal Windows 8.1 apps via `MobileServiceIncrementalLoadingCollection`, which automatically handles the calls from the controls. To use `MobileServiceIncrementalLoadingCollection` in Windows apps, do the following:
MobileServiceIncrementalLoadingCollection items;
items = todoTable.Where(todoItem => todoItem.Complete == false)
.ToIncrementalLoadingCollection();
ListBox lb = new ListBox();
lb.ItemsSource = items;
To use the new collection on Windows Phone 8 and "Silverlight" apps, use the `ToCollection` extension methods on `IMobileServiceTableQuery` and `IMobileServiceTable`. To actually load data, call `LoadMoreItemsAsync()`.
MobileServiceCollection items = todoTable.Where(todoItem => todoItem.Complete==false).ToCollection();
await items.LoadMoreItemsAsync();
When you use the collection created by calling `ToCollectionAsync` or `ToCollection`, you get a collection which can be bound to UI controls. This collection is paging-aware, i.e., a control can ask the collection to "load more items", and the collection will do it for the control. At that point there is no user code involved, the control will start the flow. However, since the collection is loading data from the network, it's expected that some times this loading will fail. To handle such failures, you may override the `OnException` method on `MobileServiceIncrementalLoadingCollection` to handle exceptions resulting from calls to `LoadMoreItemsAsync` performed by controls.
Finally, imagine that your table has many fields, but you only want to display some of them in your control. You may use the guidance in the section "[Select specific columns](#selecting)" above to select specific columns to display in the UI.
## How to: Authenticate users
Mobile Services supports authenticating and authorizing app users using a variety of external identity providers: Facebook, Google, Microsoft Account, Twitter, and Azure Active Directory. You can set permissions on tables to restrict access for specific operations to only authenticated users. You can also use the identity of authenticated users to implement authorization rules in server scripts. For more information, see the tutorial [Add authentication to your app].
Two authentication flows are supported: a _server flow_ and a _client flow_. The server flow provides the simplest authentication experience, as it relies on the provider's web authentication interface. The client flow allows for deeper integration with device-specific capabilities as it relies on provider-specific device-specific SDKs.
### Server flow
To have Mobile Services manage the authentication process in your Windows apps,
you must register your app with your identity provider. Then in your mobile service, you need to configure the application ID and secret provided by your provider. For more information, see the tutorial [Add authentication to your app].
Once you have registered your identity provider, simply call the [LoginAsync method] with the [MobileServiceAuthenticationProvider] value of your provider. For example, the following code initiates a server flow sign-in by using Facebook.
private MobileServiceUser user;
private async System.Threading.Tasks.Task Authenticate()
{
while (user == null)
{
string message;
try
{
user = await client
.LoginAsync(MobileServiceAuthenticationProvider.Facebook);
message =
string.Format("You are now logged in - {0}", user.UserId);
}
catch (InvalidOperationException)
{
message = "You must log in. Login Required";
}
var dialog = new MessageDialog(message);
dialog.Commands.Add(new UICommand("OK"));
await dialog.ShowAsync();
}
}
If you are using an identity provider other than Facebook, change the value of [MobileServiceAuthenticationProvider] above to the value for your provider.
In this case, Mobile Services manages the OAuth 2.0 authentication flow by displaying the sign-in page of the selected provider and generating a Mobile Services authentication token after successful sign-on with the identity provider. The [LoginAsync method] returns a [MobileServiceUser], which provides both the [userId] of the authenticated user and the [MobileServiceAuthenticationToken], as a JSON web token (JWT). This token can be cached and re-used until it expires. For more information, see [Caching the authentication token].
### Client flow
Your app can also independently contact the identity provider and then provide the returned token to Mobile Services for authentication. This client flow enables you to provide a single sign-in experience for users or to retrieve additional user data from the identity provider.
#### Single sign-in using a token from Facebook or Google
In the most simplified form, you can use the client flow as shown in this snippet for Facebook or Google.
var token = new JObject();
// Replace access_token_value with actual value of your access token obtained
// using the Facebook or Google SDK.
token.Add("access_token", "access_token_value");
private MobileServiceUser user;
private async System.Threading.Tasks.Task Authenticate()
{
while (user == null)
{
string message;
try
{
// Change MobileServiceAuthenticationProvider.Facebook
// to MobileServiceAuthenticationProvider.Google if using Google auth.
user = await client
.LoginAsync(MobileServiceAuthenticationProvider.Facebook, token);
message =
string.Format("You are now logged in - {0}", user.UserId);
}
catch (InvalidOperationException)
{
message = "You must log in. Login Required";
}
var dialog = new MessageDialog(message);
dialog.Commands.Add(new UICommand("OK"));
await dialog.ShowAsync();
}
}
#### Single sign-in using Microsoft Account with the Live SDK
To be able to authenticate users, you must register your app at the Microsoft account Developer Center. You must then connect this registration with your mobile service. Complete the steps in [Register your app to use a Microsoft account login](mobile-services-how-to-register-microsoft-authentication.md) to create a Microsoft account registration and connect it to your mobile service. If you have both Windows Store and Windows Phone 8/Silverlight versions of your app, register the Windows Store version first.
The following code authenticates using Live SDK and uses the returned token to sign-in to your mobile service.
private LiveConnectSession session;
//private static string clientId = "";
private async System.Threading.Tasks.Task AuthenticateAsync()
{
// Get the URL the mobile service.
var serviceUrl = App.MobileService.ApplicationUri.AbsoluteUri;
// Create the authentication client for Windows Store using the mobile service URL.
LiveAuthClient liveIdClient = new LiveAuthClient(serviceUrl);
//// Create the authentication client for Windows Phone using the client ID of the registration.
//LiveAuthClient liveIdClient = new LiveAuthClient(clientId);
while (session == null)
{
// Request the authentication token from the Live authentication service.
// The wl.basic scope is requested.
LiveLoginResult result = await liveIdClient.LoginAsync(new string[] { "wl.basic" });
if (result.Status == LiveConnectSessionStatus.Connected)
{
session = result.Session;
// Get information about the logged-in user.
LiveConnectClient client = new LiveConnectClient(session);
LiveOperationResult meResult = await client.GetAsync("me");
// Use the Microsoft account auth token to sign in to Mobile Services.
MobileServiceUser loginResult = await App.MobileService
.LoginWithMicrosoftAccountAsync(result.Session.AuthenticationToken);
// Display a personalized sign-in greeting.
string title = string.Format("Welcome {0}!", meResult.Result["first_name"]);
var message = string.Format("You are now logged in - {0}", loginResult.UserId);
var dialog = new MessageDialog(message, title);
dialog.Commands.Add(new UICommand("OK"));
await dialog.ShowAsync();
}
else
{
session = null;
var dialog = new MessageDialog("You must log in.", "Login Required");
dialog.Commands.Add(new UICommand("OK"));
await dialog.ShowAsync();
}
}
}
### Caching the authentication token
In some cases, the call to the login method can be avoided after the first time the user authenticates. You can use [PasswordVault] for Windows Store apps to cache the current user identity the first time they log in and every subsequent time you check whether you already have the user identity in our cache. When the cache is empty, you still need to send the user through the login process.
// After logging in
PasswordVault vault = new PasswordVault();
vault.Add(new PasswordCredential("Facebook", user.UserId, user.MobileServiceAuthenticationToken));
// Log in
var creds = vault.FindAllByResource("Facebook").FirstOrDefault();
if (creds != null)
{
user = new MobileServiceUser(creds.UserName);
user.MobileServiceAuthenticationToken = vault.Retrieve("Facebook", creds.UserName).Password;
}
else
{
// Regular login flow
user = new MobileServiceuser( await client
.LoginAsync(MobileServiceAuthenticationProvider.Facebook, token);
var token = new JObject();
// Replace access_token_value with actual value of your access token
token.Add("access_token", "access_token_value");
}
// Log out
client.Logout();
vault.Remove(vault.Retrieve("Facebook", user.UserId));
For Windows Phone apps, you may encrypt and cache data using the [ProtectedData] class and store sensitive information in isolated storage.
## How to: Handle errors
There are several ways to encounter, validate, and work around errors in Mobile Services.
As an example, server scripts are registered in a mobile service and can be used to perform a wide range of operations on data being inserted and updated, including validation and data modification. Imagine defining and registering a server script that validate and modify data, like so:
function insert(item, user, request)
{
if (item.text.length > 10) {
request.respond(statusCodes.BAD_REQUEST, { error: "Text cannot exceed 10 characters" });
} else {
request.execute();
}
}
This server-side script validates the length of string data sent to the mobile service and rejects strings that are too long, in this case longer than 10 characters.
Now that the mobile service is validating data and sending error responses on the server-side, you can update your .NET app to be able to handle error responses from validation.
private async void InsertTodoItem(TodoItem todoItem)
{
// This code inserts a new TodoItem into the database. When the operation completes
// and Mobile Services has assigned an Id, the item is added to the CollectionView
try
{
await todoTable.InsertAsync(todoItem);
items.Add(todoItem);
}
catch (MobileServiceInvalidOperationException e)
{
// Handle error
}
}
## How to: Work with untyped data
The .NET client is designed for strongly typed scenarios. However, sometimes, a more loosely typed experience is convenient; for example, this could be when dealing with objects with open schema. That scenario is enabled as follows. In queries, you forego LINQ and use the wire format.
// Get an untyped table reference
IMobileServiceTable untypedTodoTable = client.GetTable("TodoItem");
// Lookup untyped data using OData
JToken untypedItems = await untypedTodoTable.ReadAsync("$filter=complete eq 0&$orderby=text");
You get back JSON values that you can use like a property bag. For more information on JToken and Json.NET, see [Json.NET](http://json.codeplex.com/)
## How to: Design unit tests
The value returned by `MobileServiceClient.GetTable` and the queries are interfaces. That makes them easily "mockable" for testing purposes, so you could create a `MyMockTable : IMobileServiceTable` that implements your testing logic.
## How to: Customize the client
This section shows ways in which you can customize the request headers and customize the serialization of JSON objects in the response.
### How to: Customize request headers
To support your specific app scenario, you might need to customize communication with the mobile service. For example, you may want to add a custom header to every outgoing request or even change responses status codes. You can do this by providing a custom DelegatingHandler, as in the following example:
public async Task CallClientWithHandler()
{
MobileServiceClient client = new MobileServiceClient(
"AppUrl",
"AppKey" ,
new MyHandler()
);
IMobileServiceTable todoTable = client.GetTable();
var newItem = new TodoItem { Text = "Hello world", Complete = false };
await table.InsertAsync(newItem);
}
public class MyHandler : DelegatingHandler
{
protected override async Task
SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// Add a custom header to the request.
request.Headers.Add("x-my-header", "my value");
var response = await base.SendAsync(request, cancellationToken);
// Set a differnt response status code.
response.StatusCode = HttpStatusCode.ServiceUnavailable;
return response;
}
}
This code adds a new **x-my-header** header in the request and arbitrarily sets the response code to unavailable. In a real-world scenario, you would set the response status code based on some custom logic required by your app.
### How to: Customize serialization
The Mobile Services client library uses Json.NET to convert a JSON response into .NET objects on the client. You can configure the behavior of this serialization between .NET types and JSON in the messages. The [MobileServiceClient](http://msdn.microsoft.com/library/microsoft.windowsazure.mobileservices.mobileserviceclient.aspx) class exposes a `SerializerSettings` property of type [JsonSerializerSettings](http://james.newtonking.com/projects/json/help/?topic=html/T_Newtonsoft_Json_JsonSerializerSettings.htm)
Using this property, you may set one of the many Json.NET properties, such as the following:
var settings = new JsonSerializerSettings();
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
client.SerializerSettings = settings;
This property converts all properties to lower case during serialization.
[What is Mobile Services]: #what-is
[Concepts]: #concepts
[How to: Create the Mobile Services client]: #create-client
[How to: Create a table reference]: #instantiating
[How to: Query data from a mobile service]: #querying
[Filter returned data]: #filtering
[Sort returned data]: #sorting
[Return data in pages]: #paging
[Select specific columns]: #selecting
[Look up data by ID]: #lookingup
[How to: Bind data to user interface in a mobile service]: #binding
[How to: Insert data into a mobile service]: #inserting
[How to: Modify data in a mobile service]: #modifying
[How to: Delete data in a mobile service]: #deleting
[How to: Use Optimistic Concurrency]: #optimisticconcurrency
[How to: Authenticate users]: #authentication
[How to: Handle errors]: #errors
[How to: Design unit tests]: #unit-testing
[How to: Query data from a mobile service]: #querying
[How to: Customize the client]: #customizing
[How to: Work with untyped data]: #untyped
[Customize request headers]: #headers
[Customize serialization]: #serialization
[Next steps]: #nextsteps
[Caching the authentication token]: #caching
[How to: Call a custom API]: #custom-api
[Add authentication to your app]: mobile-services-dotnet-backend-windows-universal-dotnet-get-started-users.md
[PasswordVault]: http://msdn.microsoft.com/library/windows/apps/windows.security.credentials.passwordvault.aspx
[ProtectedData]: http://msdn.microsoft.com/library/system.security.cryptography.protecteddata%28VS.95%29.aspx
[LoginAsync method]: http://msdn.microsoft.com/library/windowsazure/microsoft.windowsazure.mobileservices.mobileserviceclientextensions.loginasync.aspx
[MobileServiceAuthenticationProvider]: http://msdn.microsoft.com/library/windowsazure/microsoft.windowsazure.mobileservices.mobileserviceauthenticationprovider.aspx
[MobileServiceUser]: http://msdn.microsoft.com/library/windowsazure/microsoft.windowsazure.mobileservices.mobileserviceuser.aspx
[UserID]: http://msdn.microsoft.com/library/windowsazure/microsoft.windowsazure.mobileservices.mobileserviceuser.userid.aspx
[MobileServiceAuthenticationToken]: http://msdn.microsoft.com/library/windowsazure/microsoft.windowsazure.mobileservices.mobileserviceuser.mobileserviceauthenticationtoken.aspx
[ASCII control codes C0 and C1]: http://en.wikipedia.org/wiki/Data_link_escape_character#C1_set
[CLI to manage Mobile Services tables]: https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-command-line-tools/#Commands_to_manage_mobile_services
[Optimistic Concurrency Tutorial]: mobile-services-windows-store-dotnet-handle-database-conflicts.md
[MobileServiceClient]: https://msdn.microsoft.com/library/azure/microsoft.windowsazure.mobileservices.mobileserviceclient.aspx
[IncludeTotalCount]: http://msdn.microsoft.com/library/windowsazure/dn250560.aspx
[Skip]: http://msdn.microsoft.com/library/windowsazure/dn250573.aspx
[Take]: http://msdn.microsoft.com/library/windowsazure/dn250574.aspx
[Fiddler]: http://www.telerik.com/fiddler
[Custom API in Azure Mobile Services Client SDKs]: http://blogs.msdn.com/b/carlosfigueira/archive/2013/06/19/custom-api-in-azure-mobile-services-client-sdks.aspx
[InvokeApiAsync]: http://msdn.microsoft.com/library/azure/microsoft.windowsazure.mobileservices.mobileserviceclient.invokeapiasync.aspx
================================================
FILE: docs/mobile-services-how-to-register-active-directory-authentication.md
================================================
# Register your apps to use an Azure Active Directory Account login
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
> [AZURE.SELECTOR]
- [Azure Active Directory](./
mobile-services-how-to-register-active-directory-authentication.md)
- [Facebook](./
mobile-services-how-to-register-facebook-authentication.md)
- [Google](./
mobile-services-how-to-register-google-authentication.md)
- [Microsoft account](./
mobile-services-how-to-register-microsoft-authentication.md)
- [Twitter](./
mobile-services-how-to-register-twitter-authentication.md)
## Overview
This topic shows you how to register your apps to be able to use Azure Active Directory as an authentication provider for your mobile service.
## Registering your app
>[AZURE.NOTE] The steps outlined in this topic are intended to be used with [Add Authentication to your Mobile Services app](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-users.md) tutorial when you want to use [Service-directed login operations](http://msdn.microsoft.com/library/azure/dn283952.aspx) with your app. Alternatively, if your app has a requirement for [client-directed login operations](http://msdn.microsoft.com/library/azure/jj710106.aspx) for Azure Active Directory and a .NET backend mobile service you should start with the [Authenticate your app with Active Directory Authentication Library Single Sign-On](mobile-services-windows-store-dotnet-adal-sso-authentication.md) tutorial.
1. Log on to the [Azure classic portal], navigate to your mobile service, click the **Identity** tab, then scroll down to the **Azure active directory** identity provider section and copy the **App URL** shown there.

2. Navigate to **Active Directory** in the [classic portal], click your directory then **Domains** and make a note of your directory's default domain.
3. Click **Applications** > **Add** > **Add an application my organization is developing**.
4. In the Add Application Wizard, enter a **Name** for your application and click the **Web application and/or Web API** type.

5. In the **Sign-on URL** box, paste the app URL value you copied from your mobile service. Enter the same unique value in the **App ID URI** box, then click to continue.

6. After the application has been added, click the **Configure** tab and copy the **Client ID** for the app.
>[AZURE.NOTE]For a .NET backend mobile service, you must also edit the **Reply URL** value under **Single Sign-on** to be the URL of your mobile service appended with the path, _signin-aad_. For example, `https://todolist.azure-mobile.net/signin-aad`
7. Return to your mobile service's **Identity** tab and paste the copied **Client ID** value for the azure active directory identity provider.

8. In the **Allowed Tenants** list, type the domain of the directory in which you registered the application (such as `contoso.onmicrosoft.com`), then click **Save**.
You are now ready to use an Azure Active Directory for authentication in your app.
[Azure classic portal]: https://manage.windowsazure.com/
[classic portal]: https://manage.windowsazure.com/
================================================
FILE: docs/mobile-services-how-to-register-facebook-authentication.md
================================================
# Register your apps for Facebook authentication with Mobile Services
> [AZURE.SELECTOR]
- [Azure Active Directory](./
mobile-services-how-to-register-active-directory-authentication.md)
- [Facebook](./
mobile-services-how-to-register-facebook-authentication.md)
- [Google](./
mobile-services-how-to-register-google-authentication.md)
- [Microsoft account](./
mobile-services-how-to-register-microsoft-authentication.md)
- [Twitter](./
mobile-services-how-to-register-twitter-authentication.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This topic shows you how to register your apps to be able to use Facebook to authenticate with Azure Mobile Services. This page supports the [Get Started with Authentication](mobile-services-ios-get-started-users.md) tutorial which shows how to log users into your app. If this is your first experience with Mobile Services, please complete the tutorial [Get Started with Mobile Services](mobile-services-ios-get-started.md).
To complete the procedure in this topic, you must have a Facebook account that has a verified email address and a mobile phone number. To create a new Facebook account, go to [facebook.com](http://go.microsoft.com/fwlink/p/?LinkId=268285).
1. Navigate to the [Facebook Developers](http://go.microsoft.com/fwlink/p/?LinkId=268285) website and sign-in with your Facebook account credentials.
2. (Optional) If you have not already registered, click **My Apps** then click **Register as a Developer**, accept the policy and follow the registration steps.
3. Click **My Apps** > **Add a New App** > **Website** > **Skip and Create App ID**.
4. In **Display Name**, enter a unique name for your app, choose a **Category** for you app, then click **Create App ID** and complete the security check. This takes you to the developer dashboard for your new Facebook app.
5. On the **App Secret** field, click **Show**, provide your password if requested, then make a note of the values of **App ID** and **App Secret**. You will uses these later to configure your application in Azure.
> [AZURE.NOTE] **Security Note**
The app secret is an important security credential. Do not share this secret with anyone or distribute it within a client application.
5. In the left navigation bar, click **Settings**, type the domain of your mobile service in **App Domains**, enter an optional **Contact Email**, click **Add Platform** and select **Website**.
![][3]
6. Type the URL of your mobile service in **Site URL**, then click **Save Changes**.
7. Click **Show**, provide your password if requested, then make a note of the values of **App ID** and **App Secret**.
![][5]
>[AZURE.IMPORTANT] The app secret is an important security credential. Do not share this secret with anyone or distribute it with your app.
8. Click the **Advanced** tab, type one of the following URL formats in **Valid OAuth redirect URIs**, then click **Save Changes**:
+ **.NET backend**: `https://.azure-mobile.net/signin-facebook`
+ **JavaScript backend**: `https://.azure-mobile.net/login/facebook`
>[AZURE.NOTE]Make sure that you use the correct redirect URL path format for your type of Mobile Services backend, using the *HTTPS* scheme. When this is incorrect, authentication will not succeed.
12. The Facebook account which was used to register the application is an administrator of the app. At this point, only administrators can sign into this application. To authenticate other Facebook accounts, click **App Review** and enable **Make todolist-complete-nodejs public** to enable general public access using Facebook authentication.
You are now ready to use a Facebook login for authentication in your app by providing the App ID and App Secret values to Mobile Services.
[3]: ./media/mobile-services-how-to-register-facebook-authentication/mobile-services-facebook-configure-app.png
[5]: ./media/mobile-services-how-to-register-facebook-authentication/mobile-services-facebook-completed.png
[Facebook Developers]: http://go.microsoft.com/fwlink/p/?LinkId=268286
[Get started with authentication]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-users-dotnet/
[Azure Mobile Services]: http://azure.microsoft.com/services/mobile-services/
================================================
FILE: docs/mobile-services-how-to-register-google-authentication.md
================================================
# Register your apps for Google login with Mobile Services
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
> [AZURE.SELECTOR]
- [Azure Active Directory](./
mobile-services-how-to-register-active-directory-authentication.md)
- [Facebook](./
mobile-services-how-to-register-facebook-authentication.md)
- [Google](./
mobile-services-how-to-register-google-authentication.md)
- [Microsoft account](./
mobile-services-how-to-register-microsoft-authentication.md)
- [Twitter](./
mobile-services-how-to-register-twitter-authentication.md)
This topic shows you how to register your apps to be able to use Google to authenticate with Azure Mobile Services.
>[AZURE.NOTE] This tutorial is about [Azure Mobile Services](https://azure.microsoft.com/services/mobile-services/), a solution to help you build scalable mobile applications for any platform. Mobile Services makes it easy to sync data, authenticate users, and send push notifications. This page supports the [Get Started with Authentication](mobile-services-ios-get-started-users.md) tutorial, which shows how to sign in users to your app.
If this is your first experience with Mobile Services, please complete the tutorial [Get Started with Mobile Services](mobile-services-ios-get-started.md).
To complete the procedure in this topic, you must have a Google account that has a verified email address. To create a new Google account, go to accounts.google.com.
3. Navigate to the [Google apis](http://go.microsoft.com/fwlink/p/?LinkId=268303) website, sign-in with your Google account credentials, click **Create Project**, provide a **Project name**, then click **Create**.
4. In the **Products & services** drop down menu, click **API Manager**, then under **Social APIs** click **Google+ API** > **Enable API**.
5. Click **Credentials** > **OAuth consent screen**, then select your **Email address**, enter a **Product Name**, and click **Save**.
6. In the **Credentials** tab, click **Add credentials** > **OAuth 2.0 client ID**, then select **Web application**.
7. Type your mobile service URL in **Authorized JavaScript Origins**, replace the generated URL in **Authorized Redirect URI** with one of the following URL formats, and then click **Create**:
+ **.NET backend**: `https://.azure-mobile.net/signin-google`
+ **JavaScript backend**: `https://.azure-mobile.net/login/google`
>[AZURE.NOTE]Make sure that you use the correct redirect URL path format for your type of Mobile Services backend. When this is incorrect, authentication will not succeed.
8. On the next screen, make a note of the values of the client ID and client secret.
> [AZURE.IMPORTANT] The client secret is an important security credential. Do not share this secret with anyone or distribute it within a client application.
You are now ready to configure your mobile service to use Google sign-in for authentication in your app.
[Google apis]: http://go.microsoft.com/fwlink/p/?LinkId=268303
[Get started with authentication]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-users-dotnet/
================================================
FILE: docs/mobile-services-how-to-register-microsoft-authentication.md
================================================
# Register your app to use Microsoft account for authentication
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
> [AZURE.SELECTOR]
- [Azure Active Directory](./
mobile-services-how-to-register-active-directory-authentication.md)
- [Facebook](./
mobile-services-how-to-register-facebook-authentication.md)
- [Google](./
mobile-services-how-to-register-google-authentication.md)
- [Microsoft account](./
mobile-services-how-to-register-microsoft-authentication.md)
- [Twitter](./
mobile-services-how-to-register-twitter-authentication.md)
## Overview
This topic shows you how to register your mobile app to be able to use Microsoft account as an identity provider with Azure Mobile Services. The same steps apply for both service-directed authentication and client-directed authentication using the Live SDK.
## Register your Windows Store app at the Windows Dev Center
Windows Store apps must first be registered with the Windows Dev Center. By registering, your Windows app will be able to use single sign-on behaviors.
>[AZURE.NOTE]Windows Phone 8, Windows Phone 8.1 Silverlight, and non-Windows apps can skip this section.
1. If you have not already registered your app, navigate to the [Windows Dev Center](https://dev.windows.com/dashboard/Application/New), log on with your Microsoft account, type a name for your app, then click **Reserve app name**.
3. Open your Windows app project in Visual Studio, then in Solution Explorer right-click the Windows Store app project, click **Store** > **Associate App with the Store...**.

5. In the wizard, click **Sign in** and sign-in with your Microsoft account, select the app name you reserved, then click **Next** > **Associate**.
6. (Optional) For a universal Windows 8.1 app, repeat steps 4 and 5 for the Windows Phone Store project.
6. Back in the Windows Dev Center page for your new app, click **Services** > **Push notifications**.
7. In the **Push notifications** page, click **Live Services site** under **Windows Push Notification Services (WNS) and Microsoft Azure Mobile Services**.
This displays the Microsoft account app settings page for your app.
8. Make a note of the **Package SID** value. You can save this SID in the Azure portal to both enable single sign-on and push notifications for your Windows app.
Next, you will configure Microsoft account authentication for your Windows app, starting with step 4 in the next section.
## Configure your Microsoft account registration and connect to Mobile Services
If you have already registered your Windows app in the previous section, you can skip to step 2.
1. For a non-Windows Store app, navigate to the [My Applications](http://go.microsoft.com/fwlink/p/?LinkId=262039) page in the Microsoft account Developer Center, log on with your Microsoft account (if required), click **Create application**, type an **Application name**, then click **I accept**.
This reserves you app name with Microsoft account and displays the Microsoft account page for your app.
2. In the Microsoft account page for your app, click **API Settings**, enable **Mobile or desktop client app**, set the mobile service URL as the **Target domain**, then supply one of the following URL formats in **Redirect URL** and click **Save**:
+ **.NET backend**: `https://.azure-mobile.net/signin-microsoft`
+ **JavaScript backend**: `https://.azure-mobile.net/login/microsoftaccount`
>[AZURE.NOTE]Make sure that you use the correct redirect URL path format for your type of Mobile Services backend. When this is incorrect, authentication will not succeed. The **Root domain** should fill in automatically.

4. Click **App Settings** and make a note of the values of the **Client ID**, **Client secret** and **Package SID**.

> [AZURE.NOTE] The client secret is an important security credential. Do not share the client secret with anyone or distribute it with your app. Only Windows Store app registrations will see a Package SID field.
4. In the [Azure classic portal], click the **Identity** tab for the mobile service, enter the client ID, client secret and package SID obtained from your identity provider, then click **Save**.
>[AZURE.NOTE]You do not need to supply a Package SID value for a Windows Phone 8, Windows Phone Store 8.1 Silverlight, or a non-Windows app.
Both your mobile service and your app are now configured to work with Microsoft account.
[Submit an app page]: http://go.microsoft.com/fwlink/p/?LinkID=266582
[My Applications]: http://go.microsoft.com/fwlink/p/?LinkId=262039
[Azure classic portal]: https://manage.windowsazure.com/
================================================
FILE: docs/mobile-services-how-to-register-twitter-authentication.md
================================================
# Register your apps for Twitter login with Mobile Services
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
> [AZURE.SELECTOR]
- [Azure Active Directory](./
mobile-services-how-to-register-active-directory-authentication.md)
- [Facebook](./
mobile-services-how-to-register-facebook-authentication.md)
- [Google](./
mobile-services-how-to-register-google-authentication.md)
- [Microsoft account](./
mobile-services-how-to-register-microsoft-authentication.md)
- [Twitter](./
mobile-services-how-to-register-twitter-authentication.md)
This topic shows you how to register your apps to be able to use Twitter to authenticate with Azure Mobile Services.
>[AZURE.NOTE] This tutorial is about [Azure Mobile Services](https://azure.microsoft.com/services/mobile-services/), a solution to help you build scalable mobile applications for any platform. Mobile Services makes it easy to sync data, authenticate users, and send push notifications. This page supports the [Add authentication to your app](mobile-services-ios-get-started-users.md) tutorial which shows how to sign users into your app. If this is your first experience with Mobile Services, please complete the tutorial [Get Started with Mobile Services](mobile-services-ios-get-started.md).
To complete the procedure in this topic, you must have a Twitter account that has a verified email address. To create a new Twitter account, go to twitter.com.
1. Navigate to the [Twitter Developers](http://go.microsoft.com/fwlink/p/?LinkId=268300) website, sign-in with your Twitter account credentials, and click **Create new app**.
2. Type the **Name**, **Description**, and **Website** values for your app, then type one of the following URL formats in **Callback URL**.
+ **.NET backend**: `https://.azure-mobile.net/signin-twitter`
+ **JavaScript backend**: `https://.azure-mobile.net/login/twitter`
>[AZURE.NOTE]Make sure that you use the correct redirect URL path format for your type of Mobile Services backend. When this is incorrect, authentication will not succeed.
![][2]
3. At the bottom the page, read and accept the terms, and then click **Create your Twitter application**.
This registers the app displays the application details.
6. Click the **Keys and Access Tokens** tab in your app dashboard and make a note of the values of **Consumer key** and **Consumer secret**.
> [AZURE.NOTE] The consumer secret is an important security credential. Do not share this secret with anyone or distribute it with your app.
7. Click the **Settings** tab, scroll down and make sure the **Allow this application to be used to sign in with Twitter** checkbox is checked, then click **Update Settings**.
You are now ready to use a Twitter login for authentication in your app by providing the consumer key and consumer secret values to Mobile Services.
[1]: ./media/mobile-services-how-to-register-twitter-authentication/mobile-services-twitter-developers.png
[2]: ./media/mobile-services-how-to-register-twitter-authentication/mobile-services-twitter-register-app1.png
[Twitter Developers]: http://go.microsoft.com/fwlink/p/?LinkId=268300
[Get started with authentication]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-users-dotnet/
================================================
FILE: docs/mobile-services-how-to-use-multiple-clients-single-service.md
================================================
# Supporting multiple device platforms from a single mobile service
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
One of the major benefits of using Azure Mobile Services in your mobile app development is the ability to use a single backend service that supports your app on multiple client platforms. Mobile Services provides native client libraries for all major device platforms, which makes it easier to develop apps using a single backend service and by using cross-platform developer tools. This topic discusses considerations for getting your app running on multiple client platforms while using a single mobile service backend.
## Cross-platform push notifications
Mobile Services uses Azure Notification Hubs for sending push notifications to your client apps on all major device platforms. Notification Hubs provide a consistent and unified infrastructure for creating and managing device registrations and for sending cross-platform push notifications. Notification Hubs supports sending push notifications by using the following platform-specific notification services:
+ Apple Push Notification Service (APNS) for iOS apps
+ Google Cloud Messaging (GCM) service for Android apps
+ Windows Notification Service (WNS) for Windows Store, Windows Phone 8.1 Store, and universal Windows apps
+ Microsoft Push Notification Service (MPNS) for Windows Phone Silverlight apps
For more information, see [Azure Notification Hubs].
Client registrations are created by using the register function in the platform-specific Mobile Services client library or by using the Mobile Services REST APIs. Notification Hubs supports two kinds of device registrations:
+ **Native registration** Native registrations are tailored to the platform-specific push notification service. When sending notifications to devices registered using native registrations, you must call platform-specific APIs in your mobile service. To send a notification to devices on multiple platforms requires multiple platform-specific calls.
+ **Template registration** Notification Hubs also supports platform-specific template registrations. By using template registrations, you can use a single API call to send a notification to your app running on any registered platform. For more information, see [Send cross-platform notifications to users].
Tables in the following sections link to the client-specific tutorials that show you how to implement push notifications from both .NET and JavaScript backend mobile services.
### .NET backend
In a .NET backend mobile service, you send notifications by calling the [SendAsync] method on the [PushClient](http://msdn.microsoft.com/library/azure/microsoft.windowsazure.mobile.service.notifications.pushclient.aspx) object obtained from the [ApiServices.Push](http://msdn.microsoft.com/library/azure/microsoft.windowsazure.mobile.service.apiservices.push.aspx) property. The push notification sent (native or template) depends on the specific [IPushMessage](http://msdn.microsoft.com/library/azure/microsoft.windowsazure.mobile.service.notifications.ipushmessage.aspx)-derived object that is passed to the [SendAsync] method, as shown in the following table:
|Platform |[APNS](mobile-services-dotnet-backend-ios-get-started-push.md)|[GCM](mobile-services-dotnet-backend-android-get-started-push.md) |[WNS](mobile-services-dotnet-backend-windows-store-dotnet-get-started-push.md) | MPNS
|-----|-----|----|----|-----|
|Native|[ApplePushMessage](http://msdn.microsoft.com/library/azure/microsoft.windowsazure.mobile.service.applepushmessage.aspx) |[GooglePushMessage](http://msdn.microsoft.com/library/azure/microsoft.windowsazure.mobile.service.googlepushmessage.aspx) |[WindowsPushMessage](http://msdn.microsoft.com/library/azure/microsoft.windowsazure.mobile.service.windowspushmessage.aspx) | [MpnsPushMessage](http://msdn.microsoft.com/library/azure/microsoft.windowsazure.mobile.service.mpnspushmessage.aspx) |
The following code sends a push notification from a .NET backend service to all iOS and Windows Store device registrations:
// Define a push notification for APNS.
ApplePushMessage apnsMessage = new ApplePushMessage(item.Text, TimeSpan.FromHours(1));
// Define a push notification for WNS.
WindowsPushMessage wnsMessage = new WindowsPushMessage();
wnsMessage.XmlPayload = @"" +
@"" +
@"" + item.Text + @"" +
@"";
// Send push notifications to all registered iOS and Windows Store devices.
await Services.Push.SendAsync(apnsMessage);
await Services.Push.SendAsync(wnsMessage);
For examples of how to send push notifications to the other native client platforms, click the platform links in the header of the above table.
When you use template client registrations rather than native client registrations, you can send the same notification with only a single call to [SendAsync], supplying a [TemplatePushMessage] object, as follows:
// Create a new template message and add the 'message' parameter.
var templatePayload = new TemplatePushMessage();
templatePayload.Add("message", item.Text);
// Send a push notification to all template registrations.
await Services.Push.SendAsync(templatePayload);
### JavaScript backend
In a JavaScript backend mobile service, you send notifications by calling the **send** method on the platform-specific object obtained from the global [push object], as shown in the following table:
|Platform |[APNS](mobile-services-javascript-backend-ios-get-started-push.md)|[GCM](mobile-services-javascript-backend-android-get-started-push.md) |[WNS](mobile-services-javascript-backend-windows-store-dotnet-get-started-push.md) |[MPNS](mobile-services-javascript-backend-windows-phone-get-started-push.md)|
|-----|-----|----|----|-----|
|Native|[apns object](http://msdn.microsoft.com/library/azure/jj839711.aspx) |[gcm object](http://msdn.microsoft.com/library/azure/dn126137.aspx) |[wns object](http://msdn.microsoft.com/library/azure/jj860484.aspx) | [mpns object](http://msdn.microsoft.com/library/azure/jj871025.aspx) |
The following code sends push notification to all Android and Windows Phone registrations:
// Define a push notification for GCM.
var gcmPayload =
'{"data":{"message" : item.text }}';
// Define the payload for a Windows Phone toast notification.
var mpnsPayload = '' +
'' +
'New Item' + item.text +
'';
// Send push notifications to all registered Android and Windows Phone 8.0 devices.
push.mpns.send(null, mpnsPayload, 'toast', 22, {
success: function(pushResponse) {
// Push succeeds.
},
error: function (pushResponse) {
// Push fails.
}
});
push.gcm.send(null, gcmPayload, {
success: function(pushResponse) {
// Push succeeds.
},
error: function (pushResponse) {
// Push fails.
}
});
For examples of how to send push notifications to the other native client platforms, click the platform links in the header of the above table.
When you use template client registrations rather than native client registrations, you can send the same notification with only a single call the **send** function on the global [push object], supplying a template message payload, as follows:
// Create a new template message with the 'message' parameter.
var templatePayload = { "message": item.text };
// Send a push notification to all template registrations.
push.send(null, templatePayload, {
success: function(pushResponse) {
// Push succeeds.
},
error: function (pushResponse) {
// Push fails.
}
});
## Cross-platform app development
Developing native mobile device apps for all of the major mobile device platforms requires you (or your organization) to have expertise in at least Objective-C, Java, and C# or JavaScript programming languages. Because of the expense of developing across these disparate platforms, some developers choose a fully web browser-based experience for their apps. However, such web-based experiences cannot access most of the native resources that provide the rich experience that users have come to expect on their mobile devices.
Cross-platform tools are available that provide a richer native experience on a mobile device, while still sharing a single code base, usually JavaScript. Mobile Services makes it easy to create and manage a backend service for cross-platform app development platforms by providing quickstart tutorials for the following development platforms:
+ [**PhoneGap**](https://go.microsoft.com/fwLink/p/?LinkID=390707)**/**[**Cordova**](http://cordova.apache.org/) PhoneGap (a distribution of the Apache Cordova project) is a free and open source framework that lets you use standardized web APIs, HTML and JavaScript to develop a single app that runs on Android, iOS and Windows devices. PhoneGap provides a web view based UI, but with a user experience enhanced by accessing native resources on the device, such as such as push notifications, the accelerometer, camera, storage, geolocation, and the in-app browser. For more information, see the [PhoneGap quickstart tutorial][PhoneGap].
Visual Studio now also enables you to build cross-platform Cordova apps by using the Multi-Device Hybrid Apps extension for Visual Studio, which is pre-release software. For more information, see [Getting Started with Multi-Device Hybrid Apps Using HTML and JavaScript](http://msdn.microsoft.com/library/dn771545.aspx).
+ [**Sencha Touch**](http://go.microsoft.com/fwlink/p/?LinkId=509988) Sencha Touch provides a set of controls, optimized for touch screens, that provide a like-native experience on a wide variety of mobile devices from a single HTML and JavaScript code base. Sencha Touch can be used along with PhoneGap or Cordova libraries to provide users access to native device resources. For more information, see the [Sencha Touch quickstart tutorial][Sencha].
+ [**Xamarin**](https://go.microsoft.com/fwLink/p/?LinkID=330242) Xamarin lets you create fully native apps for both iOS and Android devices, with fully native UI and access to all device resources. Xamarin apps are coded in C# instead of Objective-C and Java. This enables .NET developers to publish apps to iOS and Android and share code from Windows projects. Xamarin provides a fully native user experience on both iOS and Android devices from C# code. This enables you to reuse some of your Mobile Services code from Windows apps on iOS and Android devices. For more information, see [Xamarin development](#xamarin) below.
[Azure Notification Hubs]: /develop/net/how-to-guides/service-bus-notification-hubs/
[SSO Windows Store]: https://azure.microsoft.com/develop/mobile/tutorials/single-sign-on-windows-8-dotnet/
[SSO Windows Phone]: https://azure.microsoft.com/develop/mobile/tutorials/single-sign-on-wp8/
[Tutorials and resources]: https://azure.microsoft.com/develop/mobile/resources/
[Get started with Notification Hubs]: /manage/services/notification-hubs/getting-started-windows-dotnet/
[Send cross-platform notifications to users]: /manage/services/notification-hubs/notify-users-xplat-mobile-services/
[Get started with push Windows dotnet]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-push-dotnet-vs2012/
[Get started with push Windows js]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-push-js-vs2012/
[Get started with push Windows Phone]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-push-wp8/
[Get started with push iOS]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-push-ios/
[Get started with push Android]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-push-android/
[Dynamic schema]: http://msdn.microsoft.com/library/windowsazure/jj193175.aspx
[How to use a .NET client with Mobile Services]: documentation/articles/mobile-services-windows-dotnet-how-to-use-client-library/
[push object]: http://msdn.microsoft.com/library/windowsazure/jj554217.aspx
[TemplatePushMessage]:http://msdn.microsoft.com/library/azure/microsoft.windowsazure.mobile.service.templatepushmessage.aspx
[PhoneGap]: mobile-services-javascript-backend-phonegap-get-started.md
[Sencha]: partner-sencha-mobile-services-get-started.md
[Appcelerator]: partner-appcelerator-mobile-services-javascript-backend-appcelerator-get-started.md
[SendAsync]: http://msdn.microsoft.com/library/microsoft.windowsazure.mobile.service.notifications.pushclient.sendasync.aspx
[What's next for Windows Phone 8 developers]: http://msdn.microsoft.com/library/windows/apps/dn655121(v=vs.105).aspx
[Building universal Windows apps for all Windows devices]: http://go.microsoft.com/fwlink/p/?LinkId=509905
[Universal Windows app project for Azure Mobile Services using MVVM]: http://code.msdn.microsoft.com/Universal-Windows-app-for-db3564de
================================================
FILE: docs/mobile-services-how-to-use-server-scripts.md
================================================
# Work with a JavaScript backend mobile service
This article provides detailed information about and examples of how to work with a JavaScript backend in Azure Mobile Services.
## Introduction
In a JavaScript backend mobile service, you can define custom business logic as JavaScript code that's stored and executed on the server. This server script code is assigned to one of the following server functions:
+ [Insert, read, update, or delete operations on a given table][Table operations].
+ [Scheduled jobs][Job Scheduler].
+ [HTTP methods defined in a custom API][Custom API anchor].
The signature of the main function in the server script depends on the context of where the script is used. You can also define common script code as nodes.js modules that are shared across scripts. For more information, see [Source control and shared code][Source control, shared code, and helper functions].
For descriptions of individual server script objects and functions, see [Mobile Services server script reference].
## Table operations
A table operation script is a server script that is registered to an operation on a table—insert, read, update, or delete (*del*). This section describes how to work with table operations in a JavaScript backend, which includes the following sections:
+ [Overview of table operations][Basic table operations]
+ [How to: Register for table operations]
+ [How to: Override the default response]
+ [How to: Override execute success]
+ [How to: Override default error handling]
+ [How to: Generate unique ID values](#generate-guids)
+ [How to: Add custom parameters]
+ [How to: Work with table users][How to: Work with users]
### Overview of table operations
The name of the script must match the kind of operation for which it is registered. Only one script can be registered for a given table operation. The script is executed every time that the given operation is invoked by a REST request—for example, when a POST request is received to insert an item into the table. Mobile Services does not preserve state between script executions. Because a new global context is created every time a script is run, any state variables that are defined in the script are reinitialized. If you want to store state from one request to another, create a table in your mobile service, and then read and write the state to the table. For more information, see [How to: Access tables from scripts].
You write table operation scripts if you need to enforce customized business logic when the operation is executed. For example, the following script rejects insert operations where the string length of the `text` field is greater than ten characters:
function insert(item, user, request) {
if (item.text.length > 10) {
request.respond(statusCodes.BAD_REQUEST,
'Text length must be less than 10 characters');
} else {
request.execute();
}
}
A table script function always takes three arguments.
- The first argument varies depending on the table operation.
- For inserts and updates, it is an **item** object, which is a JSON representation of the row being affected by the operation. This allows you to access column values by name, for example, *item.Owner*, where *Owner* is one of the names in the JSON representation.
- For a delete, it is the ID of the record to delete.
- And for a read, it is a [query object] that specifies the rowset to return.
- The second argument is always a [user object][User object] that represents the user that submitted the request.
- The third argument is always a [request object][request object], by which you can control execution of the requested operation and the response that's sent to the client.
Here are the canonical main-function signatures for the table operations:
+ [Insert][insert function]: `function insert (item, user, request) { ... }`
+ [Update][update function]: `function update (item, user, request) { ... }`
+ [Delete][delete function]: `function del (id, user, request) { ... }`
+ [Read][read function]: `function read (query, user, request) { ... }`
>[AZURE.NOTE]A function that's registered to the delete operation must be named _del_ because delete is a reserved keyword in JavaScript.
Every server script has a main function, and may have optional helper functions. Even though a server script may have been created for a specific table, it can also reference other tables in the same database. You can also define common functions as modules that can be shared across scripts. For more information, see [Source control and shared code][Source control, shared code, and helper functions].
### How to: Register table scripts
You can define server scripts that are registered to a table operation in one of the following ways:
+ In the [Azure classic portal]. Scripts for table operations are accessed in the **Scripts** tab for a given table. The following shows the default code registered to the insert script for the `TodoItem` table. You can override this code with your own custom business logic.
![1][1]
To learn how to do this, see [Validate and modify data in Mobile Services by using server scripts].
+ By using source control. When you have source control enabled, simply create a file named `
`.``.js in the .\service\table subfolder in your git repository, where `
` is the name of the table and `` is the table operation being registered. For more information, see [Source control and shared code][Source control, shared code, and helper functions].
+ From the command prompt by using the Azure command line tool. For more information, see [Using the command line tool].
A table operation script must call at least one of the following functions of the [request object] to make sure that the client receives a response.
+ **execute function**: The operation is completed as requested and the standard response is returned.
+ **respond function**: A custom response is returned.
> [AZURE.IMPORTANT] When a script has a code path in which neither **execute** nor **respond** is invoked, the operation may become unresponsive.
The following script calls the **execute** function to complete the data operation requested by the client:
function insert(item, user, request) {
request.execute();
}
In this example, the item is inserted into the database and the appropriate status code is returned to the user.
When the **execute** function is called, the `item`, [query][query object], or `id` value that was passed as the first argument into the script function is used to perform the operation. For an insert, update or query operation, you can modify the item or query before you call **execute**:
function insert(item, user, request) {
item.scriptComment =
'this was added by a script and will be saved to the database';
request.execute();
}
function update(item, user, request) {
item.scriptComment =
'this was added by a script and will be saved to the database';
request.execute();
}
function read(query, user, request) {
// Only return records for the current user
query.where({ userid: user.userId});
request.execute();
}
>[AZURE.NOTE]In a delete script, changing the value of the supplied userId variable does not affect which record gets deleted.
For more examples, see [Read and write data], [Modify the request] and [Validate data].
### How to: Override the default response
You can also use a script to implement validation logic that can override the default response behavior. If validation fails, just call the **respond** function instead of the **execute** function and write the response to the client:
function insert(item, user, request) {
if (item.userId !== user.userId) {
request.respond(statusCodes.FORBIDDEN,
'You may only insert records with your userId.');
} else {
request.execute();
}
}
In this example, the request is rejected when the inserted item does not have a `userId` property that matches the `userId` of the [user object] that's supplied for the authenticated client. In this case, a database operation (*insert*) does not occur, and a response that has a 403 HTTP status code and a custom error message is returned to the client. For more examples, see [Modify the response].
### How to: Override execute success
By default in a table operation, the **execute** function writes responses automatically. However, you can pass two optional parameters to the execute function that override its behavior on success and/or on error.
By passing in a **success** handler when you call execute, you can modify the results of a query before you write them to the response. The following example calls `execute({ success: function(results) { ... })` to perform additional work after data is read from the database but before the response is written:
function read(query, user, request) {
request.execute({
success: function(results) {
results.forEach(function(r) {
r.scriptComment =
'this was added by a script after querying the database';
});
request.respond();
}
});
}
When you provide a **success** handler to the **execute** function, you must also call the **respond** function as part of the **success** handler so that the runtime knows that the script has completed and that a response can be written. When you call **respond** without passing any arguments, Mobile Services generates the default response.
>[AZURE.NOTE]You can call **respond** without arguments to invoke the default response only after you first call the **execute** function.
### How to: Override default error handling
The **execute** function can fail if there is a loss of connectivity to the database, an invalid object, or an incorrect query. By default when an error occurs, server scripts log the error and write an error result to the response. Because Mobile Services provides default error handling, you don't have to handle errors that may occur in the service.
You can override the default error handling by implementing explicit error handling if you want a particular compensating action or when you want to use the global console object to write more detailed information to the log. Do this by supplying an **error** handler to the **execute** function:
function update(item, user, request) {
request.execute({
error: function(err) {
// Do some custom logging, then call respond.
request.respond();
}
});
}
When you provide an error handler, Mobile Services returns an error result to the client when **respond** is called.
You can also provide both a **success** and an **error** handler if you wish.
### How to: Generate unique ID values
Mobile Services supports unique custom string values for the table's **id** column. This allows applications to use custom values such as email addresses or user names for the ID.
String IDs provide you with the following benefits:
+ IDs are generated without making a round-trip to the database.
+ Records are easier to merge from different tables or databases.
+ IDs values can integrate better with an application's logic.
When a string ID value is not set on an inserted records, Mobile Services generates a unique value for the ID. You can generate your own unique ID values in server scripts. The script example below generates a custom GUID and assigns it to a new record's ID. This is similar to the id value that Mobile Services would generate if you didn't pass in a value for a record's ID.
// Example of generating an id. This is not required since Mobile Services
// will generate an id if one is not passed in.
item.id = item.id || newGuid();
request.execute();
function newGuid() {
var pad4 = function(str) { return "0000".substring(str.length) + str; };
var hex4 = function () { return pad4(Math.floor(Math.random() * 0x10000 /* 65536 */ ).toString(16)); };
return (hex4() + hex4() + "-" + hex4() + "-" + hex4() + "-" + hex4() + "-" + hex4() + hex4() + hex4());
}
When an application provides a value for an ID, Mobile Services stores it as-is. This includes leading or trailing white spaces. White space are not trimmed from value.
The value for the `id` must be unique and it must not include characters from the following sets:
+ Control characters: [0x0000-0x001F] and [0x007F-0x009F]. For more information, see [ASCII control codes C0 and C1](http://en.wikipedia.org/wiki/Data_link_escape_character#C1_set).
+ Printable characters: **"**(0x0022), **\+** (0x002B), **/** (0x002F), **?** (0x003F), **\\** (0x005C), **`** (0x0060)
+ The ids "." and ".."
You can also use integer IDs for your tables. To use an integer ID, you must create your table with the `mobile table create` command using the `--integerId` option. This command is used with the Command-line Interface (CLI) for Azure. For more information on using the CLI, see [CLI to manage Mobile Services tables](https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-command-line-tools/#Mobile_Tables).
### How to: Access custom parameters
When you send a request to your mobile service, you can include custom parameters in the URI of the request to instruct your table operation scripts how to process a given request. You then modify your script to inspect the parameter to determine the processing path.
For example, the following URI for a POST request tells the service to not permit the insertion of a new *TodoItem* that has the same text value:
https://todolist.azure-mobile.net/tables/TodoItem?duplicateText=false
These custom query parameters are accessed as JSON values from the **parameters** property of the [request object]. The **request** object is supplied by Mobile Services to any function registered to a table operation. The following server script for the insert operation checks the value of the `duplicateText` parameter before the insert operation is run:
function insert(item, user, request) {
var todoItemTable = tables.getTable('TodoItem');
// Check the supplied custom parameter to see if
// we should allow duplicate text items to be inserted.
if (request.parameters.duplicateText === 'false') {
// Find all existing items with the same text
// and that are not marked 'complete'.
todoItemTable.where({
text: item.text,
complete: false
}).read({
success: insertItemIfNotComplete
});
} else {
request.execute();
}
function insertItemIfNotComplete(existingItems) {
if (existingItems.length > 0) {
request.respond(statusCodes.CONFLICT,
"Duplicate items are not allowed.");
} else {
// Insert the item as normal.
request.execute();
}
}
}
Note that in **insertItemIfNotComplete** the **execute** function of the [request object] is invoked to insert the item when there is no duplicate text; otherwise the **respond** function is invoked to notify the client of the duplicate.
Note the syntax of the call to the **success** function in the above code:
}).read({
success: insertItemIfNotComplete
});
In JavaScript it is a compact version of the lengthier equivalent:
success: function(results)
{
insertItemIfNotComplete(results);
}
### How to: Work with users
In Azure Mobile Services, you can use an identity provider to authenticate users. For more information, see [Get started with authentication]. When an authenticated user invokes a table operation, Mobile Services uses the [user object] to supply information about the user to the registered script function. The **userId** property can be used to store and retrieve user-specific information. The following example sets the owner property of an item based on the **userId** of an authenticated user:
function insert(item, user, request) {
item.owner = user.userId;
request.execute();
}
The next example adds an additional filter to the query based on the **userId** of an authenticated user. This filter restricts the result to only items that belong to the current user:
function read(query, user, request) {
query.where({
owner: user.userId
});
request.execute();
}
## Custom APIs
This section describes how you create and work with custom API endpoints, which includes the following sections:
+ [Overview of custom APIs](#custom-api-overview)
+ [How to: Define a custom API]
+ [How to: Implement HTTP methods]
+ [How to: Send and receive data as XML]
+ [How to: Work with users and headers in a custom API]
+ [How to: Define multiple routes in a custom API]
### Overview of custom APIs
A custom API is an endpoint in your mobile service that is accessed by one or more of the standard HTTP methods: GET, POST, PUT, PATCH, DELETE. A separate function export can be defined for each HTTP method supported by the custom API, all in a single script file. The registered script is invoked when a request to the custom API using the given method is received. For more information, see [Custom API].
When custom API functions are called by the Mobile Services runtime, both a [request][request object] and [response][response object] object are supplied. These objects expose the functionality of the [express.js library], which can be leveraged by your scripts. The following custom API named **hello** is a very simple example that returns _Hello, world!_ in response to a POST request:
exports.post = function(request, response) {
response.send(200, "{ message: 'Hello, world!' }");
}
The **send** function on the [response object] returns your desired response to the client. This code is invoked by sending a POST request to the following URL:
https://todolist.azure-mobile.net/api/hello
The global state is maintained between executions.
### How to: Define a custom API
You can define server scripts that are registered to HTTP methods in a custom API endpoint in one of the following ways:
+ In the [Azure classic portal]. Custom API scripts are created and modified in the **API** tab. The server script code is in the **Scripts** tab of a given custom API. The following shows the script that is invoked by a POST request to the `CompleteAll` custom API endpoint.
![2][2]
Access permissions to custom API methods are assigned in the Permissions tab. To see how this custom API was created, see [Call a custom API from the client].
+ By using source control. When you have source control enabled, simply create a file named ``.js in the .\service\api subfolder in your git repository, where `` is the name of the custom API being registered. This script file contains an _exported_ function for each HTTP method exposed by the custom API. Permissions are defined in a companion .json file. For more information, see [Source control and shared code][Source control, shared code, and helper functions].
+ From the command prompt by using the Azure command line tool. For more information, see [Using the command line tool].
### How to: Implement HTTP methods
A custom API can handle one or more of the HTTP methods, GET, POST, PUT, PATCH, and DELETE. An exported function is defined for each HTTP method handled by the custom API. A single custom API code file can export one or all of the following functions:
exports.get = function(request, response) { ... };
exports.post = function(request, response) { ... };
exports.patch = function(request, response) { ... };
exports.put = function(request, response) { ... };
exports.delete = function(request, response) { ... };
The custom API endpoint cannot be called using an HTTP method that has not been implemented in the server script, and a 405 (Method Not Allowed) error response is returned. Separate permission levels can be assigned to each support HTTP method.
### How to: Send and receive data as XML
When clients store and retrieve data, Mobile Services uses JavaScript Object Notation (JSON) to represent data in the message body. However, there are scenarios where you instead want to use an XML payload. For example, Windows Store apps have a built-in periodic notifications functionality that requires the service to emit XML. For more information, see [Define a custom API that supports periodic notifications].
The following **OrderPizza** custom API function returns a simple XML document as the response payload:
exports.get = function(request, response) {
response.set('content-type', 'application/xml');
var xml = '';
response.send(200, xml);
};
This custom API function is invoked by an HTTP GET request to the following endpoint:
https://todolist.azure-mobile.net/api/orderpizza
### How to: Work with users and headers in a custom API
In Azure Mobile Services, you can use an identity provider to authenticate users. For more information, see [Get started with authentication]. When an authenticated user requests a custom API, Mobile Services uses the [user object] to provide information about the user to custom API code. The [user object] is accessed from the user property of the [request object]. The **userId** property can be used to store and retrieve user-specific information.
The following **OrderPizza** custom API function sets the owner property of an item based on the **userId** of an authenticated user:
exports.post = function(request, response) {
var userTable = request.service.tables.getTable('user');
userTable.lookup(request.user.userId, {
success: function(userRecord) {
callPizzaAPI(userRecord, request.body, function(orderResult) {
response.send(201, orderResult);
});
}
});
};
This custom API function is invoked by an HTTP POST request to the following endpoint:
https://.azure-mobile.net/api/orderpizza
You can also access a specific HTTP header from the [request object], as shown in the following code:
exports.get = function(request, response) {
var header = request.header('my-custom-header');
response.send(200, "You sent: " + header);
};
This simple example reads a custom header named `my-custom-header`, then returns the value in the response.
### How to: Define multiple routes in a custom API
Mobile Services enables you to define multiple paths, or routes, in a custom API. For example, HTTP GET requests to the following URLs in a **calculator** custom API will invoke an **add** or **subtract** function, respectively:
+ `https://.azure-mobile.net/api/calculator/add`
+ `https://.azure-mobile.net/api/calculator/sub`
Multiple routes are defined by exporting a **register** function, which is passed an **api** object (similar to the [express object in express.js]) that is used to register routes under the custom API endpoint. The following example implements the **add** and **sub** methods in the **calculator** custom API:
exports.register = function (api) {
api.get('add', add);
api.get('sub', subtract);
}
function add(req, res) {
var result = parseInt(req.query.a) + parseInt(req.query.b);
res.send(200, { result: result });
}
function subtract(req, res) {
var result = parseInt(req.query.a) - parseInt(req.query.b);
res.send(200, { result: result });
}
The **api** object passed to the **register** function exposes a function for each HTTP method (**get**, **post**, **put**, **patch**, **delete**). These functions register a route to a defined function for a specific HTTP method. Each function takes two parameters, the first is the route name and the second is the function registered to the route.
The two routes in the above custom API example can be invoked by HTTP GET requests as follows (shown with the response):
+ `https://.azure-mobile.net/api/calculator/add?a=1&b=2`
{"result":3}
+ `https://.azure-mobile.net/api/calculator/sub?a=3&b=5`
{"result":-2}
## Job Scheduler
Mobile Services enables you to define server scripts that are executed either as jobs on a fixed schedule or on-demand from the Azure classic portal. Scheduled jobs are useful for performing periodic tasks such as cleaning-up table data and batch processing. For more information, see [Schedule jobs].
Scripts that are registered to scheduled jobs have a main function with the same name as the scheduled job. Because a scheduled script is not invoked by an HTTP request, there is no context that can be passed by the server runtime and the function takes no parameters. Like other kinds of scripts, you can have subroutine functions and require shared modules. For more information, see [Source control, shared code, and helper functions].
### How to: Define scheduled job scripts
A server script can be assigned to a job that's defined in the Mobile Services Scheduler. These scripts belong to the job and are executed according to the job schedule. (You can also use the [Azure classic portal] to run jobs on demand.) A script that defines a scheduled job has no parameters because Mobile Services doesn't pass it any data; it's executed as a regular JavaScript function and doesn't interact with Mobile Services directly.
You define scheduled jobs in one of the following ways:
+ In the [Azure classic portal] in the **Script** tab in the scheduler:
![3][3]
For more information about how to do this, see [Schedule backend jobs in Mobile Services].
+ From the command prompt by using the Azure command line tool. For more information, see [Using the command line tool].
>[AZURE.NOTE]When you have source control enabled, you can edit scheduled job script files directly in the .\service\scheduler subfolder in your git repository. For more information, see [How to: Share code by using source control].
## Source control, shared code, and helper functions
This sections shows you how to leverage source control to add your own custom node.js modules, shared code and other code reuse strategies, including the following sections:
+ [Overview of leveraging shared code](#leverage-source-control)
+ [How to: Load Node.js modules]
+ [How to: Use helper functions]
+ [How to: Share code by using source control]
+ [How to: Work with app settings]
### Overview of leveraging shared code
Because Mobile Services uses Node.js on the server, your scripts already have access to the built-in Node.js modules. You can also use source control to define your own modules or add other Node.js modules to your service.
The following are just some of the more useful modules that can be leveraged in your scripts by using the global **require** function:
+ **azure**: Exposes the functionality of the Azure SDK for Node.js. For more information, see the [Azure SDK for Node.js].
+ **crypto**: Provides crypto functionality of OpenSSL. For more information, see the [Node.js documentation][crypto API].
+ **path**: Contains utilities for working with file paths. For more information, see the [Node.js documentation][path API].
+ **querystring**: Contains utilities for working with query strings. For more information, see the [Node.js documentation][querystring API].
+ **request**: Sends HTTP requests to external REST services, such as Twitter and Facebook. For more information, see [Send HTTP request].
+ **sendgrid**: Sends email by using the Sendgrid email service in Azure. For more information, see [Send email from Mobile Services with SendGrid].
+ **url**: Contains utilities to parse and resolve URLs. For more information, see the [Node.js documentation][url API].
+ **util**: Contains various utilities, such as string formatting and object type checking. For more information, see the [Node.js documentation][util API].
+ **zlib**: Exposes compression functionality, such as gzip and deflate. For more information, see the [Node.js documentation][zlib API].
### How to: Leverage modules
Mobile Services exposes a set of modules that scripts can load by using the global **require** function. For example, a script can require **request** to make HTTP requests:
function update(item, user, request) {
var httpRequest = require('request');
httpRequest('http://www.google.com', function(err, response, body) {
...
});
}
### How to: Share code by using source control
You can use source control with the Node.js package manager (npm) to control which modules are available to your mobile service. There are two ways to do this:
+ For modules that are published to and installed by npm, use the package.json file to declare which packages you want to be installed by your mobile service. In this way, your service always has access to the latest version of the required packages. The package.json file lives in the `.\service` directory. For more information, see [Support for package.json in Azure Mobile Services].
+ For private or custom modules, you can use npm to manually install the module into the `.\service\node_modules` directory of your source control. For an example of how to manually upload a module, see [Leverage shared code and Node.js modules in your server scripts].
>[AZURE.NOTE]When `node_modules` already exists in the directory hierarchy, NPM will create the `\node-uuid` subdirectory there instead of creating a new `node_modules` in the repository. In this case, just delete the existing `node_modules` directory.
After you commit the package.json file or custom modules to the repository for your mobile service, use **require** to reference the modules by name.
>[AZURE.NOTE] Modules that you specify in package.json or upload to your mobile service are only used in your server script code. These modules are not used by the Mobile Services runtime.
### How to: Use helper functions
In addition to requiring modules, individual server scripts can include helper functions. These are functions that are separate from the main function, which can be used to factor code in the script.
In the following example, a table script is registered to the insert operation, which includes the helper function **handleUnapprovedItem**:
function insert(item, user, request) {
if (!item.approved) {
handleUnapprovedItem(item, user, request);
} else {
request.execute();
}
}
function handleUnapprovedItem(item, user, request) {
// Do something with the supplied item, user, or request objects.
}
In a script, helper functions must be declared after the main function. You must declare all variables in your script. Undeclared variables cause an error.
Helper functions can also be defined once and shared between server scripts. To share a function between scripts, functions must be exported and the script file must exist in the `.\service\shared\` directory. The following is a template for how to export a shared function in a file `.\services\shared\helpers.js`:
exports.handleUnapprovedItem = function (tables, user, callback) {
// Do something with the supplied tables or user objects and
// return a value to the callback function.
};
You can then use a function like this in a table operation script:
function insert(item, user, request) {
var helper = require('../shared/helper');
helper.handleUnapprovedItem(tables, user, function(result) {
// Do something based on the result.
request.execute();
}
}
}
In this example, you must pass both a [tables object] and a [user object] to the shared function. This is because shared scripts cannot access the global [tables object], and the [user object] only exists in the context of a request.
Script files are uploaded to the shared directory either by using [source control][How to: Share code by using source control] or by using the [command line tool][Using the command line tool].
### How to: Work with app settings
Mobile Services enables you to securely store values as app settings, which can be accessed by your server scripts at runtime. When you add data to the app settings of your mobile service, the name/value pairs are stored encrypted and you can access them in your server scripts without hard-coding them in the script file. For more information, see [App settings].
The following custom API example uses the supplied [service object] to retrieve an app setting value.
exports.get = function(request, response) {
// Get the MY_CUSTOM_SETTING value from app settings.
var customSetting =
request.service.config.appSettings.my_custom_setting;
// Do something and then send a response.
}
The following code uses the configuration module to retrieve Twitter access token values, stored in app settings, that are used in a scheduled job script:
// Get the service configuration module.
var config = require('mobileservice-config');
// Get the stored Twitter consumer key and secret.
var consumerKey = config.twitterConsumerKey,
consumerSecret = config.twitterConsumerSecret
// Get the Twitter access token from app settings.
var accessToken= config.appSettings.TWITTER_ACCESS_TOKEN,
accessTokenSecret = config.appSettings.TWITTER_ACCESS_TOKEN_SECRET;
Note that this code also retrieves Twitter consumer key values stored in the **Identity** tab in the portal. Because a **config object** is not available in table operation and scheduled job scripts, you must require the configuration module to access app settings. For a complete example, see [Schedule backend jobs in Mobile Services].
Using the command line tool
In Mobile Services, you can create, modify, and delete server scripts by using the Azure command line tool. Before uploading your scripts, make sure that you are using the following directory structure:
![4][4]
Note that this directory structure is the same as the git repository when using source control.
When uploading script files from the command line tool, you must first navigate to the `.\services\` directory. The following command uploads a script named `todoitem.insert.js` from the `table` subdirectory:
~$azure mobile script upload todolist table/todoitem.insert.js
info: Executing command mobile script upload
info: mobile script upload command OK
The following command returns information about every script file maintained in your mobile service:
~$ azure mobile script list todolist
info: Executing command mobile script list
+ Retrieving script information
info: Table scripts
data: Name Size
data: ------------------------- ----
data: table/channels.insert 1980
data: table/TodoItem.insert 5504
data: table/TodoItem.read 64
info: Shared scripts
data: Name Size
data: ---------------- ----
data: shared/helper.js 62
data: shared/uuid.js 7452
info: Scheduled job scripts
data: Job name Script name Status Interval Last run Next run
data: ---------- -------------------- -------- ----------- -------- --------
data: getUpdates scheduler/getUpdates disabled 15 [minute] N/A N/A
info: Custom API scripts
data: Name Get Put Post Patch Delete
data: ---------------------- ----------- ----------- ----------- ----------- -----------
data: completeall application application application application application
data: register_notifications application application user application application
info: mobile script list command OK
For more information, see [Commands to manage Azure Mobile Services].
## Working with tables
This section details strategies for working directly with SQL Database table data, including the following sections:
+ [Overview of working with tables](#overview-tables)
+ [How to: Access tables from scripts]
+ [How to: Perform Bulk Inserts]
+ [How to: Map JSON types to database types]
+ [Using Transact-SQL to access tables]
### Overview of working with tables
Many scenarios in Mobile Services require server scripts to access tables in the database. For example. because Mobile Services does not preserve state between script executions, any data that needs to be persisted between script executions must be stored in tables. You might also want to examine entries in a permissions table or store audit data instead of just writing to the log, where data has a limited duration and cannot be accessed programmatically.
Mobile Services has two ways of accessing tables, either by using a [table object] proxy or by composing Transact-SQL queries using the [mssql object]. The [table object] makes it easy to access table data from your sever script code, but the [mssql object] supports more complex data operations and provides the most flexibility.
### How to: Access tables from scripts
The easiest way to access tables from your script is by using the [tables object]. The **getTable** function returns a [table object] instance that's a proxy for accessing the requested table. You can then call functions on the proxy to access and change data.
Scripts registered to both table operations and scheduled jobs can access the [tables object] as a global object. This line of code gets a proxy for the *TodoItems* table from the global [tables object]:
var todoItemsTable = tables.getTable('TodoItems');
Custom API scripts can access the [tables object] from the service property of the supplied [request object]. This line of code gets [tables object] from the request:
var todoItemsTable = request.service.tables.getTable('TodoItem');
> [AZURE.NOTE] Shared functions cannot access the **tables** object directly. In a shared function, you must pass the tables object to the function.
Once you have a [table object], you can call one or more table operation functions: insert, update, delete or read. This example reads user permissions from a permissions table:
function insert(item, user, request) {
var permissionsTable = tables.getTable('permissions');
permissionsTable
.where({ userId: user.userId, permission: 'submit order'})
.read({ success: checkPermissions });
function checkPermissions(results) {
if(results.length > 0) {
// Permission record was found. Continue normal execution.
request.execute();
} else {
console.log('User %s attempted to submit an order without permissions.', user.userId);
request.respond(statusCodes.FORBIDDEN, 'You do not have permission to submit orders.');
}
}
}
The next example writes auditing information to an **audit** table:
function update(item, user, request) {
request.execute({ success: insertAuditEntry });
function insertAuditEntry() {
var auditTable = tables.getTable('audit');
var audit = {
record: 'checkins',
recordId: item.id,
timestamp: new Date(),
values: JSON.stringify(item)
};
auditTable.insert(audit, {
success: function() {
// Write to the response now that all data operations are complete
request.respond();
}
});
}
}
A final example is in the code sample here: [How to: Access custom parameters][How to: Add custom parameters].
### How to: Perform Bulk Inserts
If you use a **for** or **while** loop to directly insert a large number of items (1000, for example) into a table , you may encounter a SQL connection limit that causes some of the inserts to fail. Your request may never complete or it may return a HTTP 500 Internal Server Error. To avoid this problem, you can insert the items in batches of 10 or so. After the first batch is inserted, submit the next batch, and so on.
By using the following script, you can set the size of a batch of records to insert in parallel. We recomend that you keep the number of records small. The function **insertItems** calls itself recursively when an async insert batch has completed. The for loop at the end inserts one record at a time, and calls **insertComplete** on success and **errorHandler** on error. **insertComplete** controls whether **insertItems** will be called recursively for the next batch, or whether the job is done and the script should exit.
var todoTable = tables.getTable('TodoItem');
var recordsToInsert = 1000;
var batchSize = 10;
var totalCount = 0;
var errorCount = 0;
function insertItems() {
var batchCompletedCount = 0;
var insertComplete = function() {
batchCompletedCount++;
totalCount++;
if(batchCompletedCount === batchSize || totalCount === recordsToInsert) {
if(totalCount < recordsToInsert) {
// kick off the next batch
insertItems();
} else {
// or we are done, report the status of the job
// to the log and don't do any more processing
console.log("Insert complete. %d Records processed. There were %d errors.", totalCount, errorCount);
}
}
};
var errorHandler = function(err) {
errorCount++;
console.warn("Ignoring insert failure as part of batch.", err);
insertComplete();
};
for(var i = 0; i < batchSize; i++) {
var item = { text: "This is item number: " + totalCount + i };
todoTable.insert(item, {
success: insertComplete,
error: errorHandler
});
}
}
insertItems();
The entire code sample, and accompanying discussion, can be found in this [blog posting](http://blogs.msdn.com/b/jpsanders/archive/2013/03/20/server-script-to-insert-table-items-in-windows-azure-mobile-services.aspx). If you use this code, you can adapt it to your specific situation, and thoroughly test it.
### How to: Map JSON types to database types
The collections of data types on the client and in a Mobile Services database table are different. Sometimes they map easily to one another, and other times they don't. Mobile Services performs a number of type transformations in the mapping:
- The client language-specific types are serialized into JSON.
- The JSON representation is translated into JavaScript before it appears in server scripts.
- The JavaScript data types are converted to SQL database types when saved using the [tables object].
The transformation from client schema into JSON varies across platforms. JSON.NET is used in Windows Store and Windows Phone clients. The Android client uses the gson library. The iOS client uses the NSJSONSerialization class. The default serialization behavior of each of these libraries is used, except that date objects are converted to JSON strings that contain the date that's encoded by using ISO 8601.
When you are writing server scripts that use [insert], [update], [read] or [delete] functions, you can access the JavaScript representation of your data. Mobile Services uses the Node.js's deserialization function ([JSON.parse](http://es5.github.io/#x15.12)) to transform JSON on the wire into JavaScript objects. However Mobile Services does a transformation to extract **Date** objects from ISO 8601 strings.
When you use the [tables object] or the [mssql object], or just let your table scripts execute, the deserialized JavaScript objects are inserted into your SQL database. In that process, object properties are mapped to T-SQL types:
JavaScript property|T-SQL type
---|---
Number|Float(53)
Boolean|Bit
Date|DateTimeOffset(3)|
String|Nvarchar(max)
Buffer|Not supported
Object|Not supported
Array|Not supported
Stream|Not supported
### Using Transact-SQL to access tables
The easiest way to work table data from server scripts is by using a [table object] proxy. However, there are more advanced scenarios that are not supported by the [table object], such as as join queries and other complex queries and invoking stored procedures. In these cases, you must execute Transact-SQL statements directly against the relational table by using the [mssql object]. This object provides the following functions:
- **query**: executes a query, specified by a TSQL string; the results are returned to the **success** callback on the **options** object. The query can include parameters if the *params* parameter is present.
- **queryRaw**: like *query* except that the result set returned from the query is in a "raw" format (see example below).
- **open**: used to get a connection to your Mobile Services database, and you can then use the connection object to invoke database operations such as transactions.
These methods give you increasingly more low-level control over the query processing.
+ [How to: Run a static query]
+ [How to: Run a dynamic query]
+ [How to: Join relational tables]
+ [How to: Run a query that returns *raw* results]
+ [How to: Get access to a database connection]
#### How to: Run a static query
The following query has no parameters and returns three records from the `statusupdate` table. The rowset is in standard JSON format.
mssql.query('select top 3 * from statusupdates', {
success: function(results) {
console.log(results);
},
error: function(err) {
console.log("error is: " + err);
}
});
#### How to: Run a dynamic parameterized query
The following example implements custom authorization by reading permissions for each user from the permissions table. The placeholder (?) is replaced with the supplied parameter when the query is executed.
var sql = "SELECT _id FROM permissions WHERE userId = ? AND permission = 'submit order'";
mssql.query(sql, [user.userId], {
success: function(results) {
if (results.length > 0) {
// Permission record was found. Continue normal execution.
request.execute();
} else {
console.log('User %s attempted to submit an order without permissions.', user.userId);
request.respond(statusCodes.FORBIDDEN, 'You do not have permission to submit orders.');
}
},
error: function(err) {
console.log("error is: " + err);
}
});
#### How to: Join relational tables
You can join two tables by using the **query** method of the [mssql object] to pass in the TSQL code that implements the join. Let's assume we have some items in our **ToDoItem** table and each item in the table has a **priority** property, which corresponds to a column in the table. An item may look like this:
{ text: 'Take out the trash', complete: false, priority: 1}
Let's also assume we have an additional table called **Priority** with rows that contain a priority **number** and a text **description**. For example, the priority number 1 might have the description of "Critical", with the object looking as follows:
{ number: 1, description: 'Critical'}
We can now replace the **priority** number in our item with the text description of the priority number. We do this with a relational join of the two tables.
mssql.query('SELECT t.text, t.complete, p.description FROM ToDoItem as t INNER JOIN Priority as p ON t.priority = p.number', {
success: function(results) {
console.log(results);
},
error: function(err) {
console.log("error is: " + err);
});
The script joins the two tables and writes the results to the log. The resulting objects could look like this:
{ text: 'Take out the trash', complete: false, description: 'Critical'}
#### How to: Run a query that returns *raw* results
This example executes the query, as before, but returns the resultset in "raw" format which requires you to parse it, row by row, and column by column. A possible scenario for this is if you need access to data types that Mobile Services does not support. This code simply writes the output to the console log so you can inspect the raw format.
mssql.queryRaw('SELECT * FROM ToDoItem', {
success: function(results) {
console.log(results);
},
error: function(err) {
console.log("error is: " + err);
}
});
Here is the output from running this query. It contains metadata about each column in the table, followed by a representation of the rows and columns.
{ meta:
[ { name: 'id',
size: 19,
nullable: false,
type: 'number',
sqlType: 'bigint identity' },
{ name: 'text',
size: 0,
nullable: true,
type: 'text',
sqlType: 'nvarchar' },
{ name: 'complete',
size: 1,
nullable: true,
type: 'boolean',
sqlType: 'bit' },
{ name: 'priority',
size: 53,
nullable: true,
type: 'number',
sqlType: 'float' } ],
rows:
[ [ 1, 'good idea for the future', null, 3 ],
[ 2, 'this is important but not so much', null, 2 ],
[ 3, 'fix this bug now', null, 0 ],
[ 4, 'we need to fix this one real soon now', null, 1 ],
] }
#### How to: Get access to a database connection
You can use the **open** method to get access to the database connection. One reason to do this might be if you need to use database transactions.
Successful execution of the **open** causes the database connection to be passed into the **success** function as a parameter. You can invoke any of the following functions on the **connection** object: *close*, *queryRaw*, *query*, *beginTransaction*, *commit*, and *rollback*.
mssql.open({
success: function(connection) {
connection.query(//query to execute);
},
error: function(err) {
console.log("error is: " + err);
}
});
## Debugging and troubleshooting
The primary way to debug and troubleshoot your server scripts is by writing to the service log. By default, Mobile Services writes errors that occur during service script execution to the service logs. Your scripts can also write to the logs. Writing to logs is great way to debug your scripts and validate that they are behaving as desired.
### How to: Write output to the mobile service logs
To write to the logs, use the global [console object]. Use the **log** or **info** function to log information-level warnings. The **warning** and **error** functions log their respective levels, which are called-out in the logs.
> [AZURE.NOTE] To view the logs for your mobile service, log on to the [Azure classic portal](https://manage.windowsazure.com/), select your mobile service, and then choose the **Logs** tab.
You can also use the logging functions of the [console object] to format your messages using parameters. The following example supplies a JSON object as a parameter to the message string:
function insert(item, user, request) {
console.log("Inserting item '%j' for user '%j'.", item, user);
request.execute();
}
Notice that the string `%j` is used as the placeholder for a JSON object and that parameters are supplied in sequential order.
To avoid overloading your log, you should remove or disable calls to console.log() that aren't needed for production use.
[Introduction]: #intro
[Table operations]: #table-scripts
[Basic table operations]: #basic-table-ops
[How to: Register for table operations]: #register-table-scripts
[How to: Define table scripts]: #execute-operation
[How to: override the default response]: #override-response
[How to: Modify an operation]: #modify-operation
[How to: Override success and error]: #override-success-error
[How to: Override execute success]: #override-success
[How to: Override default error handling]: #override-error
[How to: Access tables from scripts]: #access-tables
[How to: Add custom parameters]: #access-headers
[How to: Work with users]: #work-with-users
[How to: Define scheduled job scripts]: #scheduler-scripts
[How to: Refine access to tables]: #authorize-tables
[Using Transact-SQL to access tables]: #TSQL
[How to: Run a static query]: #static-query
[How to: Run a dynamic query]: #dynamic-query
[How to: Run a query that returns *raw* results]: #raw
[How to: Get access to a database connection]: #connection
[How to: Join relational tables]: #joins
[How to: Perform Bulk Inserts]: #bulk-inserts
[How to: Map JSON types to database types]: #JSON-types
[How to: Load Node.js modules]: #modules-helper-functions
[How to: Write output to the mobile service logs]: #write-to-logs
[Source control, shared code, and helper functions]: #shared-code
[Using the command line tool]: #command-prompt
[Working with tables]: #working-with-tables
[Custom API anchor]: #custom-api
[How to: Define a custom API]: #define-custom-api
[How to: Share code by using source control]: #shared-code-source-control
[How to: Use helper functions]: #helper-functions
[Debugging and troubleshooting]: #debugging
[How to: Implement HTTP methods]: #handle-methods
[How to: Work with users and headers in a custom API]: #get-api-user
[How to: Access custom API request headers]: #get-api-headers
[Job Scheduler]: #scheduler-scripts
[How to: Define multiple routes in a custom API]: #api-routes
[How to: Send and receive data as XML]: #api-return-xml
[How to: Work with app settings]: #app-settings
[1]: ./media/mobile-services-how-to-use-server-scripts/1-mobile-insert-script-users.png
[2]: ./media/mobile-services-how-to-use-server-scripts/2-mobile-custom-api-script.png
[3]: ./media/mobile-services-how-to-use-server-scripts/3-mobile-schedule-job-script.png
[4]: ./media/mobile-services-how-to-use-server-scripts/4-mobile-source-local-cli.png
[Mobile Services server script reference]: http://msdn.microsoft.com/library/windowsazure/jj554226.aspx
[Schedule backend jobs in Mobile Services]: https://azure.microsoft.com/develop/mobile/tutorials/schedule-backend-tasks/
[request object]: http://msdn.microsoft.com/library/windowsazure/jj554218.aspx
[response object]: http://msdn.microsoft.com/library/windowsazure/dn303373.aspx
[User object]: http://msdn.microsoft.com/library/windowsazure/jj554220.aspx
[push object]: http://msdn.microsoft.com/library/windowsazure/jj554217.aspx
[insert function]: http://msdn.microsoft.com/library/windowsazure/jj554229.aspx
[insert]: http://msdn.microsoft.com/library/windowsazure/jj554229.aspx
[update function]: http://msdn.microsoft.com/library/windowsazure/jj554214.aspx
[delete function]: http://msdn.microsoft.com/library/windowsazure/jj554215.aspx
[read function]: http://msdn.microsoft.com/library/windowsazure/jj554224.aspx
[update]: http://msdn.microsoft.com/library/windowsazure/jj554214.aspx
[delete]: http://msdn.microsoft.com/library/windowsazure/jj554215.aspx
[read]: http://msdn.microsoft.com/library/windowsazure/jj554224.aspx
[query object]: http://msdn.microsoft.com/library/windowsazure/jj613353.aspx
[apns object]: http://msdn.microsoft.com/library/windowsazure/jj839711.aspx
[mpns object]: http://msdn.microsoft.com/library/windowsazure/jj871025.aspx
[wns object]: http://msdn.microsoft.com/library/windowsazure/jj860484.aspx
[table object]: http://msdn.microsoft.com/library/windowsazure/jj554210.aspx
[tables object]: http://msdn.microsoft.com/library/windowsazure/jj614364.aspx
[mssql object]: http://msdn.microsoft.com/library/windowsazure/jj554212.aspx
[console object]: http://msdn.microsoft.com/library/windowsazure/jj554209.aspx
[Read and write data]: http://msdn.microsoft.com/library/windowsazure/jj631640.aspx
[Validate data]: http://msdn.microsoft.com/library/windowsazure/jj631638.aspx
[Modify the request]: http://msdn.microsoft.com/library/windowsazure/jj631635.aspx
[Modify the response]: http://msdn.microsoft.com/library/windowsazure/jj631631.aspx
[Azure classic portal]: https://manage.windowsazure.com/
[Schedule jobs]: http://msdn.microsoft.com/library/windowsazure/jj860528.aspx
[Validate and modify data in Mobile Services by using server scripts]: https://azure.microsoft.com/develop/mobile/tutorials/validate-modify-and-augment-data-dotnet/
[Commands to manage Azure Mobile Services]: https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-command-line-tools/#Mobile_Scripts
[Windows Store Push]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-push-dotnet/
[Windows Phone Push]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-push-wp8/
[iOS Push]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-push-ios/
[Android Push]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-push-android/
[Azure SDK for Node.js]: http://go.microsoft.com/fwlink/p/?LinkId=275539
[Send HTTP request]: http://msdn.microsoft.com/library/windowsazure/jj631641.aspx
[Send email from Mobile Services with SendGrid]: https://azure.microsoft.com/develop/mobile/tutorials/send-email-with-sendgrid/
[Get started with authentication]: http://go.microsoft.com/fwlink/p/?LinkId=287177
[crypto API]: http://go.microsoft.com/fwlink/p/?LinkId=288802
[path API]: http://go.microsoft.com/fwlink/p/?LinkId=288803
[querystring API]: http://go.microsoft.com/fwlink/p/?LinkId=288804
[url API]: http://go.microsoft.com/fwlink/p/?LinkId=288805
[util API]: http://go.microsoft.com/fwlink/p/?LinkId=288806
[zlib API]: http://go.microsoft.com/fwlink/p/?LinkId=288807
[Custom API]: http://msdn.microsoft.com/library/windowsazure/dn280974.aspx
[Call a custom API from the client]: https://azure.microsoft.com/develop/mobile/tutorials/call-custom-api-dotnet/#define-custom-api
[express.js library]: http://go.microsoft.com/fwlink/p/?LinkId=309046
[Define a custom API that supports periodic notifications]: https://azure.microsoft.com/develop/mobile/tutorials/create-pull-notifications-dotnet/
[express object in express.js]: http://expressjs.com/api.html#express
[Store server scripts in source control]: https://azure.microsoft.com/develop/mobile/tutorials/store-scripts-in-source-control/
[Leverage shared code and Node.js modules in your server scripts]: https://azure.microsoft.com/develop/mobile/tutorials/store-scripts-in-source-control/#use-npm
[service object]: http://msdn.microsoft.com/library/windowsazure/dn303371.aspx
[App settings]: http://msdn.microsoft.com/library/dn529070.aspx
[config module]: http://msdn.microsoft.com/library/dn508125.aspx
[Support for package.json in Azure Mobile Services]: http://go.microsoft.com/fwlink/p/?LinkId=391036
================================================
FILE: docs/mobile-services-html-get-started-users.md
================================================
# Add authentication to your Mobile Services app
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-users.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started-users.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-users.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-get-started-users.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-windows-phone-get-started-users.md)
- [(Android | Javascript)](mobile-services-android-get-started-users.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started-users.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-users.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-users.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-users.md)
- [(HTML | Javascript)](mobile-services-html-get-started-users.md)
This topic shows you how to authenticate users in Azure Mobile Services from your HTML app, including PhoneGap or Cordova apps. In this tutorial, you add authentication to the quickstart project using an identity provider that is supported by Mobile Services. After being successfully authenticated and authorized by Mobile Services, the user ID value is displayed.
This tutorial is based on the Mobile Services quickstart. You must also first complete the tutorial [Get started with Mobile Services].
## Register your app for authentication and configure Mobile Services
1. In the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Dashboard**, and make a note of the **Mobile Service URL** value.
2. Register your app with one or more of the following authentication providers:
* [Google](./
mobile-services-how-to-register-google-authentication.md)
* [Facebook](./
mobile-services-how-to-register-facebook-authentication.md)
* [Twitter](./
mobile-services-how-to-register-twitter-authentication.md)
* [Microsoft](./
mobile-services-how-to-register-microsoft-authentication.md)
* [Azure Active Directory](./
mobile-services-how-to-register-active-directory-authentication.md).
Make a note of the client identity and client secret values generated by the provider. Do not distribute or share the client secret.
3. Back in the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Identity** > your identity provider settings, then enter the client ID and secret value from your provider.
You've now configured both your app and your mobile service to work with your auth provider. You may optionally repeat all these steps for each additional identity provider you'd like to support.
> [AZURE.IMPORTANT] Verify that you've set the correct redirect URI on your identity provider's developer site. As described in the linked instructions for each provider above, the redirect URI may be different for a .NET backend service vs. for a JavaScript backend service. An incorrectly configured redirect URI may result in the login screen not being displayed properly and the app malfunctioning in unexpected ways.
## Restrict permissions to authenticated users
To secure your endpoints, you must restrict access to only authenticated clients.
1. In the [Azure classic portal](https://manage.windowsazure.com/), navigate to your mobile service, then click **Data** > your table name (**TodoItem**) > **Permissions**.
2. Set all of the table operation permissions to **Only authenticated users**.
This ensures that all operations against the table require an authenticated user, which is required for this tutorial. You can set different permissions on each operations to support your specific scenario.
3. In the app directory, launch one of the following command files from the **server** subfolder.
+ **launch-windows** (Windows computers)
+ **launch-mac.command** (Mac OS X computers)
+ **launch-linux.sh** (Linux computers)
>[AZURE.NOTE]On a Windows computer, type `R` when PowerShell asks you to confirm that you want to run the script. Your web browser might warn you to not run the script because it was downloaded from the internet. When this happens, you must request that the browser proceed to load the script.
This starts a web server on your local computer to host the new app.
2. Open the URL http://localhost:8000/ in a web browser to start the app.
The data fails to load. This happens because the app attempts to access Mobile Services as an unauthenticated user, but the _TodoItem_ table now requires authentication.
3. (Optional) Open the script debugger for your web browser and reload the page. Verify that an access denied error occurs.
Next, you will update the app to allow authentication before requesting resources from the mobile service.
## Add authentication to the app
>[AZURE.NOTE]Because the login is performed in a popup, you should invoke the **login** method from a button's click event. Otherwise, many browsers will suppress the login window.
1. Open the project file index.html, locate the H1 element and under it add the following code snippet:
You are logged in as .
You are not logged in.
This enables you to login to Mobile Services from the page.
2. In the page.js file, locate the line of code at the very bottom of the file that calls to the refreshTodoItems function, and replace it with the following code:
function refreshAuthDisplay() {
var isLoggedIn = client.currentUser !== null;
$("#logged-in").toggle(isLoggedIn);
$("#logged-out").toggle(!isLoggedIn);
if (isLoggedIn) {
$("#login-name").text(client.currentUser.userId);
refreshTodoItems();
}
}
function logIn() {
client.login("facebook").then(refreshAuthDisplay, function(error){
alert(error);
});
}
function logOut() {
client.logout();
refreshAuthDisplay();
$('#summary').html('You must login to access data.');
}
// On page init, fetch the data and set up event handlers
$(function () {
refreshAuthDisplay();
$('#summary').html('You must login to access data.');
$("#logged-out button").click(logIn);
$("#logged-in button").click(logOut);
});
This creates a set of functions to handle the authentication process. The user is authenticated by using a Facebook login. If you are using an identity provider other than Facebook, change the value passed to the **login** method above to one of the following: *microsoftaccount*, *facebook*, *twitter*, *google*, or *aad*.
>[AZURE.IMPORTANT]In a PhoneGap app, you must also add the following plugins to the project:
>
9. Go back to the browser where your app is running, and refresh the page.
When you are successfully logged-in, the app should run without errors, and you should be able to query Mobile Services and make updates to data.
>[AZURE.NOTE]When you use Internet Explorer, you may receive the error after login: Cannot reach window opener. It may be on a different Internet Explorer zone. This occurs because the pop-up runs in a different security zone (internet) from localhost (intranet). This only affects apps during development using localhost. As a workaround, open the **Security** tab of **Internet Options**, click **Local Intranet**, click **Sites**, and disable **Automatically detect intranet network**. Remember to change this setting back when you are done testing.
## Next steps
In the next tutorial, [Authorize users with scripts], you will take the user ID value provided by Mobile Services based on an authenticated user and use it to filter the data returned by Mobile Services. Learn more about how to use Mobile Services with HTML/JavaScript in [Mobile Services HTML/JavaScript How-to Conceptual Reference]
[Register your app for authentication and configure Mobile Services]: #register
[Restrict table permissions to authenticated users]: #permissions
[Add authentication to the app]: #add-authentication
[Next Steps]:#next-steps
[4]: ./media/mobile-services-html-get-started-users/mobile-services-selection.png
[5]: ./media/mobile-services-html-get-started-users/mobile-service-uri.png
[13]: ./media/mobile-services-html-get-started-users/mobile-identity-tab.png
[14]: ./media/mobile-services-html-get-started-users/mobile-portal-data-tables.png
[15]: ./media/mobile-services-html-get-started-users/mobile-portal-change-table-perms.png
[Get started with Mobile Services]: mobile-services-html-get-started.md
[Authorize users with scripts]: mobile-services-javascript-backend-service-side-authorization.md
[Mobile Services HTML/JavaScript How-to Conceptual Reference]: mobile-services-html-how-to-use-client-library.md
================================================
FILE: docs/mobile-services-html-get-started.md
================================================
# Get started with Mobile Services
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal JavaScript | Javascript)](mobile-services-javascript-backend-windows-store-javascript-get-started.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started.md)
- [(Android | Javascript)](mobile-services-android-get-started.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started.md)
- [(HTML | Javascript)](mobile-services-html-get-started.md)
- [(PhoneGap | Javascript)](mobile-services-javascript-backend-phonegap-get-started.md)
- [(Sencha | Javascript)](partner-sencha-mobile-services-get-started.md)
>[AZURE.TIP] This topic shows you how to get started with Mobile Services as quickly as possible. It is designed for customers new to this Azure feature. If you are already familiar with Mobile Services or are looking for more in-depth information, please select a topic from the left-navigation or see the relevant links in [Next steps](#next-steps).
## Overview
This tutorial shows you how to add a cloud-based backend service to an HTML app using Azure Mobile Services. In this tutorial, you will create both a new mobile service and a simple *To do list* app that stores app data in the new mobile service. You can view the following video version of this tutorial.
> [AZURE.VIDEO mobile-get-started-html]
A screenshot from the completed app is below:
![][0]
Completing this tutorial is a prerequisite for all other Mobile Services tutorials for HTML apps. For a PhoneGap/Cordova app, see the the [PhoneGap/Cordova version](mobile-services-javascript-backend-phonegap-get-started.md) of this tutorial.
## Prerequisites
The following are required to complete this tutorial:
+ You must have one of the following web servers running on your local computer:
+ **On Windows**: IIS Express. IIS Express is installed by the [Microsoft Web Platform Installer].
+ **On MacOS X**: Python, which should already be installed.
+ **On Linux**: Python. You must install the [latest version of Python].
You can use any web server to host the app, but these are the web servers that are supported by the downloaded scripts.
+ A web browser that supports HTML5.
+ An Azure account. If you don't have an account, you can create a free trial account in just a couple of minutes. For details, see [Azure Free Trial](https://azure.microsoft.com/pricing/free-trial/?WT.mc_id=A0E0E5C02&returnurl=http%3A%2F%2Fazure.microsoft.com%2Fen-us%2Fdevelop%2Fmobile%2Ftutorials%2Fget-started-html%2F"%20target="_blank).
## Create a new mobile service
Follow these steps to create a new mobile service.
1. Log into the [Azure classic portal](https://manage.windowsazure.com/). At the bottom of the navigation pane, click **+NEW**. Expand **Compute** and **Mobile Service**, then click **Create**.

This displays the **Create a Mobile Service** dialog.
2. In the **Create a Mobile Service** dialog, select **Create a free 20 MB SQL Database**, select **JavaScript** runtime, then type a subdomain name for the new mobile service in the **URL** textbox. Click the right arrow button to go to the next page.

This displays the **Specify database settings** page.
>[AZURE.NOTE]As part of this tutorial, you create a new SQL Database instance and server. You can reuse this new database and administer it as you would any other SQL Database instance. If you already have a database in the same region as the new mobile service, you can instead choose **Use existing Database** and then select that database. The use of a database in a different region is not recommended because of additional bandwidth costs and higher latencies.
3. In **Name**, type the name of the new database, then type **Login name**, which is the administrator login name for the new SQL Database server, type and confirm the password, and click the check button to complete the process.

You have now created a new mobile service that can be used by your mobile apps.
## Create a new HTML app
Once you have created your mobile service, you can follow an easy quickstart in the Azure classic portal to either create a new app or modify an existing app to connect to your mobile service.
In this section you will create a new HTML app that is connected to your mobile service.
1. In the [Azure classic portal], click **Mobile Services**, and then click the mobile service that you just created.
2. In the quickstart tab, click **Windows** under **Choose platform** and expand **Create a new HTML app**.
![][6]
This displays the three easy steps to create and host an HTML app connected to your mobile service.
![][7]
3. Click **Create TodoItems table** to create a table to store app data.
4. Under **Download and run your app**, click **Download**.
This downloads the website files for the sample _To do list_ application that is connected to your mobile service. Save the compressed file to your local computer, and make a note of where you save it.
5. In the **Configure** tab, verify that `localhost` is already listed in the **Allow requests from host names** list under **Cross-Origin Resource Sharing (CORS)**. If it's not, type `localhost` in the **Host name** field and then click **Save**.
![][9]
> [AZURE.IMPORTANT] If you deploy the quickstart app to a web server other than localhost, you must add the host name of the web server to the **Allow requests from host names** list. For more information, see [Cross-origin resource sharing](http://msdn.microsoft.com/library/windowsazure/dn155871.aspx).
## Host and run your HTML app
The final stage of this tutorial is to host and run your new app on your local computer.
1. Browse to the location where you saved the compressed project files, expand the files on your computer, and launch one of the following command files from the **server** subfolder.
+ **launch-windows** (Windows computers)
+ **launch-mac.command** (Mac OS X computers)
+ **launch-linux.sh** (Linux computers)
> [AZURE.NOTE] On a Windows computer, type `R` when PowerShell asks you to confirm that you want to run the script. Your web browser might warn you to not run the script because it was downloaded from the internet. When this happens, you must request that the browser proceed to load the script.
This starts a web server on your local computer to host the new app.
2. Open the URL http://localhost:8000/ in a web browser to start the app.
3. In the app, type meaningful text, such as _Complete the tutorial_, in **Enter new task**, and then click **Add**.
![][10]
This sends a POST request to the new mobile service hosted in Azure. Data from the request is inserted into the TodoItem table. Items stored in the table are returned by the mobile service, and the data is displayed in the second column in the app.
> [AZURE.NOTE] You can review the code that accesses your mobile service to query and insert data, which is found in the page.js file.
4. Back in the [Azure classic portal], click the **Data** tab and then click the **TodoItems** table.
![][11]
This lets you browse the data inserted by the app into the table.
![][12]
## Next Steps
Now that you have completed the quickstart, learn how to perform additional important tasks in Mobile Services:
* **[Add authentication to your app]**
Learn how to authenticate users of your app with an identity provider.
* **[Mobile Services HTML/JavaScript How-to Conceptual Reference]**
Learn more about how to use Mobile Services with HTML/JavaScript
[Getting started with Mobile Services]:#getting-started
[Create a new mobile service]:#create-new-service
[Define the mobile service instance]:#define-mobile-service-instance
[Next Steps]:#next-steps
[0]: ./media/mobile-services-html-get-started/mobile-quickstart-completed-html.png
[6]: ./media/mobile-services-html-get-started/mobile-portal-quickstart-html.png
[7]: ./media/mobile-services-html-get-started/mobile-quickstart-steps-html.png
[9]: ./media/mobile-services-html-get-started/mobile-services-set-cors-localhost.png
[10]: ./media/mobile-services-html-get-started/mobile-quickstart-startup-html.png
[11]: ./media/mobile-services-html-get-started/mobile-data-tab.png
[12]: ./media/mobile-services-html-get-started/mobile-data-browse.png
[Add authentication to your app]: mobile-services-html-get-started-users.md
[Azure classic portal]: https://manage.windowsazure.com/
[Microsoft Web Platform Installer]: http://go.microsoft.com/fwlink/p/?LinkId=286333
[latest version of Python]: http://go.microsoft.com/fwlink/p/?LinkId=286342
[Mobile Services HTML/JavaScript How-to Conceptual Reference]: mobile-services-html-how-to-use-client-library.md
[Cross-origin resource sharing]: http://msdn.microsoft.com/library/azure/dn155871.aspx
================================================
FILE: docs/mobile-services-html-how-to-use-client-library.md
================================================
# How to use an HTML/JavaScript client for Azure Mobile Services
> [AZURE.SELECTOR]
- [Android](mobile-services-android-how-to-use-client-library.md)
- [HTML/JavaScript](mobile-services-html-how-to-use-client-library.md)
- [iOS](mobile-services-ios-how-to-use-client-library.md)
- [Managed (Windows/Xamarin)](mobile-services-dotnet-how-to-use-client-library.md)
## Overview
This guide shows you how to perform common scenarios using an HTML/JavaScript client for Azure Mobile Services, which includes Windows Store JavaScript and PhoneGap/Cordova apps. The scenarios covered include querying for data, inserting, updating, and deleting data, authenticating users, and handling errors. If you are new to Mobile Services, you should consider first completing the [Mobile Services quickstart](mobile-services-html-get-started.md). The quickstart tutorial helps you configure your account and create your first mobile service.
## What is Mobile Services
Azure Mobile Services is a highly scalable mobile application development platform that lets you add enhanced functionality to your mobile device apps by using Azure.
With Mobile Services you can:
+ **Build native and cross platform apps** - Connect your iOS, Android, Windows, or cross-platform Xamarin or Cordova (Phonegap) apps to your backend mobile service using native SDKs.
+ **Send push notifications to your users** - Send push notifications to your users of your app.
+ **Authenticate your users** - Leverage popular identity providers like Facebook and Twitter to authenticate your app users.
+ **Store data in the cloud** - Store user data in a SQL Database (by default) or in Mongo DB, DocumentDB, Azure Tables, or Azure Blobs.
+ **Build offline-ready apps with sync** - Make your apps work offline and use Mobile Services to sync data in the background.
+ **Monitor and scale your apps** - Monitor app usage and scale your backend as demand grows.
## Mobile Services Concepts
The following are important features and concepts in the Mobile Services:
+ **Application key:** a unique value that is used to limit access to your mobile service from random clients; this "key" is not a security token and is not used to authenticate users of your app.
+ **Backend:** the mobile service instance that supports your app. A mobile service is implemented either as an ASP.NET Web API project (*.NET backend* ) or as a Node.js project (*JavaScript backend*).
+ **Identity provider:** an external service, trusted by Mobile Services, that authenticates your app's users. Supported providers include: Facebook, Twitter, Google, Microsoft Account, and Azure Active Directory.
+ **Push notification:** Service-initiated message that is sent to a registered device or user using Azure Notification Hubs.
+ **Scale:** The ability to add, for an additional cost, more processing power, performance, and storage as your app becomes more popular.
+ **Scheduled job:** Custom code that is run either on a pre-determined schedule or on-demand.
For more information, see [Mobile Services Concepts](./
mobile-services-concepts-links.md).
## How to: Create the Mobile Services client
The way that you add a reference to the Mobile Services client depends on your app platform, which includes the following:
- For a web-based application, open the HTML file and add the following to the script references for the page:
- For a Windows Store app written in JavaScript/HTML, add the **WindowsAzure.MobileServices.WinJS** NuGet package to your project.
- For a PhoneGap or Cordova app, add the [Mobile Services plugin](https://github.com/Azure/azure-mobile-services-cordova) to your project. This plugin supports [push notifications](#push-notifications).
In the editor, open or create a JavaScript file, and add the following code that defines the `MobileServiceClient` variable, and supply the application URL and application key from the mobile service in the `MobileServiceClient` constructor, in that order.
var MobileServiceClient = WindowsAzure.MobileServiceClient;
var client = new MobileServiceClient('AppUrl', 'AppKey');
You must replace the placeholder `AppUrl` with the application URL of your mobile service and `AppKey` with the application key, which you obtain from the [Azure classic portal](http://manage.windowsazure.com/).
>[AZURE.IMPORTANT]The application key is intended to filter-out random request against your mobile service, and it is distributed with the application. Because this key is not encrypted, it cannot be considered secure. To truly secure your mobile service data, you must instead authenticate users before allowing access. For more information, see [How to: Authenticate users](#authentication).
## How to: Query data from a mobile service
All of the code that accesses or modifies data in the SQL Database table calls functions on the `MobileServiceTable` object. You get a reference to the table by calling the `getTable()` function on an instance of the `MobileServiceClient`.
var todoItemTable = client.getTable('todoitem');
### How to: Filter returned data
The following code illustrates how to filter data by including a `where` clause in a query. It returns all items from `todoItemTable` whose complete field is equal to `false`. `todoItemTable` is the reference to the mobile service table that we created previously. The where function applies a row filtering predicate to the query against the table. It accepts as its argument a JSON object or function that defines the row filter, and returns a query that can be further composed.
var query = todoItemTable.where({
complete: false
}).read().done(function (results) {
alert(JSON.stringify(results));
}, function (err) {
alert("Error: " + err);
});
By calling `where` on the Query object and passing an object as a parameter, we are instructing Mobile Services to return only the rows whose `complete` column contains the `false` value. Also, look at the request URI below, and notice that we are modifying the query string itself:
GET /tables/todoitem?$filter=(complete+eq+false) HTTP/1.1
You can view the URI of the request sent to the mobile service by using message inspection software, such as browser developer tools or Fiddler.
This request would normally be translated roughly into the following SQL query on the server side:
SELECT *
FROM TodoItem
WHERE ISNULL(complete, 0) = 0
The object which is passed to the `where` method can have an arbitrary number of parameters, and they'll all be interpreted as AND clauses to the query. For example, the line below:
query.where({
complete: false,
assignee: "david",
difficulty: "medium"
}).read().done(function (results) {
alert(JSON.stringify(results));
}, function (err) {
alert("Error: " + err);
});
Would be roughly translated (for the same request shown before) as
SELECT *
FROM TodoItem
WHERE ISNULL(complete, 0) = 0
AND assignee = 'david'
AND difficulty = 'medium'
The `where` statement above and the SQL query above find incomplete items assigned to "david" of "medium" difficulty.
There is, however, another way to write the same query. A `.where` call on the Query object will add an `AND` expression to the `WHERE` clause, so we could have written that in three lines instead:
query.where({
complete: false
});
query.where({
assignee: "david"
});
query.where({
difficulty: "medium"
});
Or using the fluent API:
query.where({
complete: false
})
.where({
assignee: "david"
})
.where({
difficulty: "medium"
});
The two methods are equivalent and may be used interchangeably. All the `where` calls so far take an object with some parameters, and are compared for equality against the data from the database. There is, however, another overload for the query method, which takes a function instead of the object. In this function we can then write more complex expressions, using operators such as inequality and other relational operations. In these functions, the keyword `this` binds to the server object.
The body of the function is translated into an Open Data Protocol (OData) boolean expression which is passed to a query string parameter. It is possible to pass in a function that takes no parameters, like so:
query.where(function () {
return this.assignee == "david" && (this.difficulty == "medium" || this.difficulty == "low");
}).read().done(function (results) {
alert(JSON.stringify(results));
}, function (err) {
alert("Error: " + err);
});
If passing in a function with parameters, any arguments after the `where` clause are bound to the function parameters in order. Any objects which come from the outside of the function scope MUST be passed as parameters - the function cannot capture any external variables. In the next two examples, the argument "david" is bound to the parameter `name` and in the first example, the argument "medium" is also bound to the parameter `level`. Also, the function must consist of a single `return` statement with a supported expression, like so:
query.where(function (name, level) {
return this.assignee == name && this.difficulty == level;
}, "david", "medium").read().done(function (results) {
alert(JSON.stringify(results));
}, function (err) {
alert("Error: " + err);
});
So, as long as we follow the rules, we can add more complex filters to our database queries, like so:
query.where(function (name) {
return this.assignee == name &&
(this.difficulty == "medium" || this.difficulty == "low");
}, "david").read().done(function (results) {
alert(JSON.stringify(results));
}, function (err) {
alert("Error: " + err);
});
It is possible to combine `where` with `orderBy`, `take`, and `skip`. See the next section for details.
### How to: Sort returned data
The following code illustrates how to sort data by including an `orderBy` or `orderByDescending` function in the query. It returns items from `todoItemTable` sorted ascending by the `text` field. By default, the server returns only the first 50 elements.
> [AZURE.NOTE] A server-driven page size us used by default to prevent all elements from being returned. This keeps default requests for large data sets from negatively impacting the service.
You may increase the number of items to be returned by calling `take` as described in the next section. `todoItemTable` is the reference to the mobile service table that we created previously.
var ascendingSortedTable = todoItemTable.orderBy("text").read().done(function (results) {
alert(JSON.stringify(results));
}, function (err) {
alert("Error: " + err);
});
var descendingSortedTable = todoItemTable.orderByDescending("text").read().done(function (results) {
alert(JSON.stringify(results));
}, function (err) {
alert("Error: " + err);
});
var descendingSortedTable = todoItemTable.orderBy("text").orderByDescending("text").read().done(function (results) {
alert(JSON.stringify(results));
}, function (err) {
alert("Error: " + err);
});
### How to: Return data in pages
By default, Mobile Services only returns 50 rows in a given request, unless the client explicitly asks for more data in the response. The following code shows how to implement paging in returned data by using the `take` and `skip` clauses in the query. The following query, when executed, returns the top three items in the table.
var query = todoItemTable.take(3).read().done(function (results) {
alert(JSON.stringify(results));
}, function (err) {
alert("Error: " + err);
});
Notice that the `take(3)` method was translated into the query option `$top=3` in the query URI.
The following revised query skips the first three results and returns the next three after that. This is effectively the second "page" of data, where the page size is three items.
var query = todoItemTable.skip(3).take(3).read().done(function (results) {
alert(JSON.stringify(results));
}, function (err) {
alert("Error: " + err);
});
Again, you can view the URI of the request sent to the mobile service. Notice that the `skip(3)` method was translated into the query option `$skip=3` in the query URI.
This is a simplified scenario of passing hard-coded paging values to the `take` and `skip` functions. In a real-world app, you can use queries similar to the above with a pager control or comparable UI to let users navigate to previous and next pages.
### How to: Select specific columns
You can specify which set of properties to include in the results by adding a `select` clause to your query. For example, the following code returns the `id`, `complete`, and `text` properties from each row in the `todoItemTable`:
var query = todoItemTable.select("id", "complete", "text").read().done(function (results) {
alert(JSON.stringify(results));
}, function (err) {
alert("Error: " + err);
})
Here the parameters to the select function are the names of the table's columns that you want to return.
All the functions described so far are additive, so we can just keep calling them and we'll each time affect more of the query. One more example:
query.where({
complete: false
})
.select('id', 'assignee')
.orderBy('assignee')
.take(10)
.read().done(function (results) {
alert(JSON.stringify(results));
}, function (err) {
alert("Error: " + err);
### How to: Look up data by ID
The `lookup` function takes only the `id` value, and returns the object from the database with that ID. Database tables are created with either an integer or string `id` column. A string `id` column is the default.
todoItemTable.lookup("37BBF396-11F0-4B39-85C8-B319C729AF6D").done(function (result) {
alert(JSON.stringify(result));
}, function (err) {
alert("Error: " + err);
})
## Execute an OData query operation
Mobile Services uses the OData query URI conventions for composing and executing REST queries. Not all OData queries can be composed by using the built-in query functions, especially complex filter operations like searching for a substring in a property. For these kinds of complex queries, you can pass any valid OData query option string to the `read` function, as follows:
function refreshTodoItems() {
todoItemTable.read("$filter=substringof('search_text',text)").then(function(items) {
var itemElements = $.map(items, createUiForTodoItem);
$("#todo-items").empty().append(itemElements);
$("#no-items").toggle(items.length === 0);
}, handleError);
}
>[AZURE.NOTE]When you provide a raw OData query option string into the `read` function, you cannot also use the query builder methods in the same query. In this case, you must compose your whole query as an OData query string. For more information on OData system query options, see the [OData system query options reference].
## How to: Insert data into a mobile service
The following code illustrates how to insert new rows into a table. The client requests that a row of data be inserted by sending a POST request to the mobile service. The request body contains the data to be inserted, as a JSON object.
todoItemTable.insert({
text: "New Item",
complete: false
})
This inserts data from the supplied JSON object into the table. You can also specify a callback function to be invoked when the insertion is complete:
todoItemTable.insert({
text: "New Item",
complete: false
}).done(function (result) {
alert(JSON.stringify(result));
}, function (err) {
alert("Error: " + err);
});
### Working with ID values
Mobile Services supports unique custom string values for the table's **id** column. This allows applications to use custom values such as email addresses or user names for the ID. For example, the following code inserts a new item as a JSON object, where the unique ID is an email address:
todoItemTable.insert({
id: "myemail@domain.com",
text: "New Item",
complete: false
});
String IDs provide you with the following benefits:
+ IDs are generated without making a round-trip to the database.
+ Records are easier to merge from different tables or databases.
+ IDs values can integrate better with an application's logic.
When a string ID value is not already set on an inserted record, Mobile Services generates a unique value for the ID. For more information on how to generate your own ID values, either on the client or in a .NET backend, see [How to: Generate unique ID values](mobile-services-how-to-use-server-scripts.md#generate-guids).
You can also use integer IDs for your tables. To use an integer ID, you must create your table with the `mobile table create` command using the `--integerId` option. This command is used with the Command-line Interface (CLI) for Azure. For more information on using the CLI, see [CLI to manage Mobile Services tables](https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-command-line-tools/#Mobile_Tables).
## How to: Modify data in a mobile service
The following code illustrates how to update data in a table. The client requests that a row of data be updated by sending a PATCH request to the mobile service. The request body contains the specific fields to be updated, as a JSON object. It updates an existing item in the table `todoItemTable`.
todoItemTable.update({
id: idToUpdate,
text: newText
})
The first parameter specifies the instance to update in the table, as specified by its ID.
You can also specify a callback function to be invoked when the update is complete:
todoItemTable.update({
id: idToUpdate,
text: newText
}).done(function (result) {
alert(JSON.stringify(result));
}, function (err) {
alert("Error: " + err);
});
## How to: Delete data in a mobile service
The following code illustrates how to delete data from a table. The client requests that a row of data be deleted by sending a DELETE request to the mobile service. It deletes an existing item in the table todoItemTable.
todoItemTable.del({
id: idToDelete
})
The first parameter specifies the instance to delete in the table, as specified by its ID.
You can also specify a callback function to be invoked when the delete is complete:
todoItemTable.del({
id: idToDelete
}).done(function () {
/* Do something */
}, function (err) {
alert("Error: " + err);
});
## How to: Display data in the user interface
This section shows how to display returned data objects using UI elements. To query items in `todoItemTable` and display it in a very simple list, you can run the following example code. No selection, filtering or sorting of any kind is done.
var query = todoItemTable;
query.read().then(function (todoItems) {
// The space specified by 'placeToInsert' is an unordered list element
...
var listOfItems = document.getElementById('placeToInsert');
for (var i = 0; i < todoItems.length; i++) {
var li = document.createElement('li');
var div = document.createElement('div');
div.innerText = todoItems[i].text;
li.appendChild(div);
listOfItems.appendChild(li);
}
}).read().done(function (results) {
alert(JSON.stringify(results));
}, function (err) {
alert("Error: " + err);
});
In a Windows Store app, the results of a query can be used to create a [WinJS.Binding.List] object, which can be bound as the data source for a [ListView] object. For more information, see [Data binding (Windows Store apps using JavaScript and HTML)].
## How to: Call a custom API
A custom API enables you to define custom endpoints that expose server functionality that does not map to an insert, update, delete, or read operation. By using a custom API, you can have more control over messaging, including reading and setting HTTP message headers and defining a message body format other than JSON. For an example of how to create a custom API in your mobile service, see [How to: define a custom API endpoint](mobile-services-dotnet-backend-define-custom-api.md).
You call a custom API from the client by calling the [invokeApi](https://github.com/Azure/azure-mobile-services/blob/master/sdk/Javascript/src/MobileServiceClient.js#L337) method on **MobileServiceClient**. For example, the following line of code sends a POST request to the **completeAll** API on the mobile service:
client.invokeApi("completeall", {
body: null,
method: "post"
}).done(function (results) {
var message = results.result.count + " item(s) marked as complete.";
alert(message);
refreshTodoItems();
}, function(error) {
alert(error.message);
});
For more realistic examples and a more a complete discussion of **invokeApi**, see [Custom API in Azure Mobile Services Client SDKs](http://blogs.msdn.com/b/carlosfigueira/archive/2013/06/19/custom-api-in-azure-mobile-services-client-sdks.aspx).
## How to: Authenticate users
Mobile Services supports authenticating and authorizing app users using a variety of external identity providers: Facebook, Google, Microsoft Account, and Twitter. You can set permissions on tables to restrict access for specific operations to only authenticated users. You can also use the identity of authenticated users to implement authorization rules in server scripts. For more information, see the [Get started with authentication] tutorial.
>[AZURE.NOTE] When using authentication in a PhoneGap or Cordova app, you must also add the following plugins to the project:
>
>+ https://git-wip-us.apache.org/repos/asf/cordova-plugin-device.git
>+ https://git-wip-us.apache.org/repos/asf/cordova-plugin-inappbrowser.git
Two authentication flows are supported: a _server flow_ and a _client flow_. The server flow provides the simplest authentication experience, as it relies on the provider's web authentication interface. The client flow allows for deeper integration with device-specific capabilities such as single-sign-on as it relies on provider-specific device-specific SDKs.
### Server flow
To have Mobile Services manage the authentication process in your Windows Store or HTML5 app,
you must register your app with your identity provider. Then in your mobile service, you need to configure the application ID and secret provided by your provider. For more information, see the tutorial [Add authentication to your app](mobile-services-html-get-started-users.md).
Once you have registered your identity provider, simply call the [LoginAsync method] with the [MobileServiceAuthenticationProvider] value of your provider. For example, to login with Facebook use the following code.
client.login("facebook").done(function (results) {
alert("You are now logged in as: " + results.userId);
}, function (err) {
alert("Error: " + err);
});
If you are using an identity provider other than Facebook, change the value passed to the `login` method above to one of the following: `microsoftaccount`, `facebook`, `twitter`, `google`, or `windowsazureactivedirectory`.
In this case, Mobile Services manages the OAuth 2.0 authentication flow by displaying the login page of the selected provider and generating a Mobile Services authentication token after successful login with the identity provider. The [login] function, when complete, returns a JSON object (**user**) that exposes both the user ID and Mobile Services authentication token in the **userId** and **authenticationToken** fields, respectively. This token can be cached and re-used until it expires. For more information, see [Caching the authentication token].
### Client flow
Your app can also independently contact the identity provider and then provide the returned token to Mobile Services for authentication. This client flow enables you to provide a single sign-in experience for users or to retrieve additional user data from the identity provider.
#### Facebook/Google SDK basic example
This example uses Facebook client SDK for authentication:
client.login(
"facebook",
{"access_token": token})
.done(function (results) {
alert("You are now logged in as: " + results.userId);
}, function (err) {
alert("Error: " + err);
});
This example assumes that the token provided by the respective provider SDK is stored in the `token` variable.
Twitter cannot be used for client authentication at this time.
#### Microsoft Account basic example
The following example uses the Live SDK, which supports single-sign-on for Windows Store apps by using Microsoft Account:
WL.login({ scope: "wl.basic"}).then(function (result) {
client.login(
"microsoftaccount",
{"authenticationToken": result.session.authentication_token})
.done(function(results){
alert("You are now logged in as: " + results.userId);
},
function(error){
alert("Error: " + err);
});
});
This simplified example gets a token from Live Connect, which is supplied to Mobile Services by calling the [login] function.
#### Microsoft Account complete example
The following example shows how to use the Live SDK with WinJS APIs to provide an enhanced single-sign-on experience:
// Set the mobileClient variable to client variable generated by the tooling.
var mobileClient = ;
var session = null;
var login = function () {
return new WinJS.Promise(function (complete) {
WL.login({ scope: "wl.basic" }).then(function (result) {
session = result.session;
WinJS.Promise.join([
WL.api({ path: "me", method: "GET" }),
mobileClient.login(result.session.authentication_token)
]).done(function (results) {
// Build the welcome message from the Microsoft account info.
var profile = results[0];
var title = "Welcome " + profile.first_name + "!";
var message = "You are now logged in as: "
+ mobileClient.currentUser.userId;
var dialog = new Windows.UI.Popups.MessageDialog(message, title);
dialog.showAsync().then(function () {
// Reload items from the mobile service.
refreshTodoItems();
}).done(complete);
}, function (error) {
});
}, function (error) {
session = null;
var dialog = new Windows.UI.Popups.MessageDialog("You must log in.", "Login Required");
dialog.showAsync().done(complete);
});
});
}
var authenticate = function () {
// Block until sign-in is successful.
login().then(function () {
if (session === null) {
// Authentication failed, try again.
authenticate();
}
});
}
// Initialize the Live client.
WL.init({
redirect_uri: mobileClient.applicationUrl
});
// Start the sign-in process.
authenticate();
This initializes the Live Connect client, sends a new login request to Microsoft account, sends the returned authentication token to Mobile Services, and then displays information about the signed-in user. The app does not start until authentication succeeds.
## How to: Register for push notifications
When your app is a PhoneGap or Apache Cordova HTML/JavaScript app, the native mobile platform enables you to receive push notifications on the device. The [Apache Cordova plugin for Azure Mobile Services](https://github.com/Azure/azure-mobile-services-cordova) enables you to register for push notifications with Azure Notification Hubs. The specific notification service used depends on the native device platform on which the code executes. For an example of how to do this, see the sample, [Use Microsoft Azure to push notifications to Cordova apps](https://github.com/Azure/mobile-services-samples/tree/master/CordovaNotificationsArticle).
>[AZURE.NOTE]This plugin currently only supports iOS and Android devices. For a solution that also includes Windows devices, see the article [Push Notifications to PhoneGap Apps using Notification Hubs Integration](http://blogs.msdn.com/b/azuremobile/archive/2014/06/17/push-notifications-to-phonegap-apps-using-notification-hubs-integration.aspx).
## How to: Handle errors
There are several ways to encounter, validate, and work around errors in Mobile Services.
As an example, server scripts are registered in a mobile service and can be used to perform a wide range of operations on data being inserted and updated, including validation and data modification. Imagine defining and registering a server script that validate and modify data, like so:
function insert(item, user, request) {
if (item.text.length > 10) {
request.respond(statusCodes.BAD_REQUEST, { error: "Text cannot exceed 10 characters" });
} else {
request.execute();
}
}
This server-side script validates the length of string data sent to the mobile service and rejects strings that are too long, in this case longer than 10 characters.
Now that the mobile service is validating data and sending error responses on the server-side, you can update your HTML app to be able to handle error responses from validation.
todoItemTable.insert({
text: itemText,
complete: false
})
.then(function (results) {
alert(JSON.stringify(results));
}, function (error) {
alert(JSON.parse(error.request.responseText).error);
});
To tease this out even further, you pass in the error handler as the second argument each time you perform data access:
function handleError(message) {
if (window.console && window.console.error) {
window.console.error(message);
}
}
client.getTable("tablename").read()
.then(function (data) { /* do something */ }, handleError);
## How to: Use promises
Promises provide a mechanism to schedule work to be done on a value that has not yet been computed. It is an abstraction for managing interactions with asynchronous APIs.
The `done` promise is executed as soon as the function provided to it has either successfully completed or has gotten an error. Unlike the `then` promise, it is guaranteed to throw any error that is not handled inside the function, and after the handlers have finished executing, this function throws any error that would have been returned from then as a promise in the error state. For more information, see [done].
promise.done(onComplete, onError);
Like so:
var query = todoItemTable;
query.read().done(function (results) {
alert(JSON.stringify(results));
}, function (err) {
alert("Error: " + err);
});
The `then` promise is the same as the as the `done` promise, but unlike the `then` promise, `done` is guaranteed to throw any error that is not handled inside the function. If you do not provide an error handler to `then` and the operation has an error, it does not throw an exception but rather returns a promise in the error state. For more information, see [then].
promise.then(onComplete, onError).done( /* Your success and error handlers */ );
Like so:
var query = todoItemTable;
query.read().done(function (results) {
alert(JSON.stringify(results));
}, function (err) {
alert("Error: " + err);
});
You can use promises in a number of different ways. You can chain promise operations by calling `then` or `done` on the promise that is returned by the previous `then` function. Use `then` for an intermediate stage of the operation (for example `.then().then()`), and `done` for the final stage of the operation (for example `.then().then().done()`). You can chain multiple `then` functions, because `then` returns a promise. You cannot chain more than one `done` method, because it returns undefined. [Learn more about the differences between then and done].
todoItemTable.insert({
text: "foo"
}).then(function (inserted) {
inserted.newField = 123;
return todoItemTable.update(inserted);
}).done(function (insertedAndUpdated) {
alert(JSON.stringify(insertedAndUpdated));
})
## How to: Customize client request headers
You can send custom request headers using the `withFilter` function, reading and writing arbitrary properties of the request about to be sent within the filter. You may want to add such a custom HTTP header if a server-side script needs it or may be enhanced by it.
var client = new WindowsAzure.MobileServiceClient('https://your-app-url', 'your-key')
.withFilter(function (request, next, callback) {
request.headers.MyCustomHttpHeader = "Some value";
next(request, callback);
});
Filters are used for a lot more than customizing request headers. They can be used to examine or change requests, examine or change responses, bypass networking calls, send multiple calls, etc.
## How to: Use cross-origin resource sharing
To control which websites are allowed to interact with and send requests to your mobile service, make sure to add the host name of the website you use to host it to the Cross-Origin Resource Sharing (CORS) whitelist. For a JavaScript backend mobile service, you can configure the whitelist on the Configure tab in the [Azure classic portal](https://manage.windowsazure.com). You can use wildcards if required. By default, new Mobile Services instruct browsers to permit access only from `localhost`, and Cross-Origin Resource Sharing (CORS) allows JavaScript code running in a browser on an external hostname to interact with your Mobile Service. This configuration is not necessary for WinJS applications.
[What is Mobile Services]: #what-is
[Concepts]: #concepts
[How to: Create the Mobile Services client]: #create-client
[How to: Query data from a mobile service]: #querying
[Filter returned data]: #filtering
[Sort returned data]: #sorting
[Return data in pages]: #paging
[Select specific columns]: #selecting
[Look up data by ID]: #lookingup
[How to: Display data in the user interface]: #binding
[How to: Insert data into a mobile service]: #inserting
[How to: Modify data in a mobile service]: #modifying
[How to: Delete data in a mobile service]: #deleting
[How to: Authenticate users]: #authentication
[How to: Handle errors]: #errors
[How to: Use promises]: #promises
[How to: Customize request headers]: #customizing
[How to: Use cross-origin resource sharing]: #hostnames
[Next steps]: #nextsteps
[Execute an OData query operation]: #odata-query
[then]: http://msdn.microsoft.com/library/windows/apps/br229728.aspx
[done]: http://msdn.microsoft.com/library/windows/apps/hh701079.aspx
[Learn more about the differences between then and done]: http://msdn.microsoft.com/library/windows/apps/hh700334.aspx
[how to handle errors in promises]: http://msdn.microsoft.com/library/windows/apps/hh700337.aspx
[sessionStorage]: http://msdn.microsoft.com/library/cc197062(v=vs.85).aspx
[localStorage]: http://msdn.microsoft.com/library/cc197062(v=vs.85).aspx
[ListView]: http://msdn.microsoft.com/library/windows/apps/br211837.aspx
[Data binding (Windows Store apps using JavaScript and HTML)]: http://msdn.microsoft.com/library/windows/apps/hh758311.aspx
[login]: https://github.com/Azure/azure-mobile-services/blob/master/sdk/Javascript/src/MobileServiceClient.js#L301
[ASCII control codes C0 and C1]: http://en.wikipedia.org/wiki/Data_link_escape_character#C1_set
[OData system query options reference]: http://go.microsoft.com/fwlink/p/?LinkId=444502
================================================
FILE: docs/mobile-services-ios-get-started-offline-data.md
================================================
# Get Started with Offline Data Sync in Mobile Services
> [AZURE.SELECTOR]
- [Android)](mobile-services-android-get-started-offline-data.md)
- [iOS](mobile-services-ios-get-started-offline-data.md)
- [Windows](mobile-services-windows-store-dotnet-get-started-offline-data.md)
- [Xamarin.Android](mobile-services-xamarin-android-get-started-offline-data.md)
- [Xamarin.iOS](mobile-services-xamarin-ios-get-started-offline-data.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
Offline sync allows you to view, add, or modify data in a mobile app even when there is no network connection. In this tutorial, you'll learn how your app can automatically store changes in a local offline database and sync those changes whenever it's back online.
Offline sync has several advantages:
* Improves app responsiveness by caching server data locally on device
* Makes apps resilient against intermittent network connectivity
* Allows you to create and modify data even with little or no connectivity
* Syncs data across multiple devices
* Detects conflicts when same record is modified by two devices
> [AZURE.NOTE] To complete this tutorial, you need an Azure account. If you don't have an account, you can sign up for an Azure trial and get [free mobile services that you can keep using even after your trial ends](https://azure.microsoft.com/pricing/details/mobile-services/). For details, see [Azure Free Trial](https://azure.microsoft.com/pricing/free-trial/?WT.mc_id=AE564AB28 target="_blank").
This tutorial is based on the [Mobile Services Quick Start tutorial], which you must complete first. Let's first review the code related to offline sync already in the Quick Start.
## Review Mobile Services Sync Code
Azure Mobile Services offline sync allows end users to interact with a local database when the network is not accessible. To use these features in your app, you initialize the sync context of `MSClient` and reference a local store. Then reference your table through the `MSSyncTable` interface.
* In **QSTodoService.m**, notice the type of member `syncTable` is `MSSyncTable`. Offline sync uses this instead of `MSTable`. When a sync table is used, all operations go to the local store and are synchronized with the remote service only with explicit push and pull operations.
```
@property (nonatomic, strong) MSSyncTable *syncTable;
```
To get a reference to a sync table, use the method `syncTableWithName`. To remove offline sync functionality, use `tableWithName` instead.
* In **QSTodoService.m**, before table operations are performed, the local store is initialized in `QSTodoService.init`:
```
MSCoreDataStore *store = [[MSCoreDataStore alloc] initWithManagedObjectContext:context];
self.client.syncContext = [[MSSyncContext alloc] initWithDelegate:nil dataSource:store callback:nil];
```
This creates a local store using the `MSCoreDataStore` interface. You may provide a different local store by implementing the `MSSyncContextDataSource` protocol.
The first parameter of `initWithDelegate` specifies a conflict handler, but since we've passed `nil`, we get the default conflict handler which fails on any conflict. For details on how to implement a custom conflict handler, see [Handling Conflicts with Offline Support for Mobile Services].
* In **QSTodoService.m**, `syncData` first pushes new changes, and then calls `pullData` to get data from the remote service. In `syncData`, we first call `pushWithCompletion` on the sync context. This method is a member of `MSSyncContext` -- rather than the sync table itself -- because it pushes changes across all tables. Only records that are modified in some way locally -- through creation, update, or delete operations -- are sent to the server. At the end of `syncData`, we call the helper `pullData`.
In this example, the push operation is not strictly necessary. If there are changes pending in the sync context for the table that is doing a push operation, pull always issues a push first. However, if you have more than one sync table, call push explicitly to have consistency across tables.
```
-(void)syncData:(QSCompletionBlock)completion
{
// push all changes in the sync context, then pull new data
[self.client.syncContext pushWithCompletion:^(NSError *error) {
[self logErrorIfNotNil:error];
[self pullData:completion];
}];
}
```
* Next in **QSTodoService.m**, `pullData` gets new data that matches a query. `pullData` calls `MSSyncTable.pullWithQuery` to retrieve remote data and store it locally. `pullWithQuery` also allows you to specify a query to filter the records you wish to retrieve. In this example, the query just retrieves all records in the remote `TodoItem` table.
The second parameter to `pullWithQuery` is a query ID for _incremental sync_. Incremental sync retrieves only those records modified since the last sync, using the record's `UpdatedAt` timestamp, called `ms_updatedAt` in the local store. The query ID is descriptive string that is unique for each logical query in your app. To opt-out of incremental sync, pass `nil` as the query ID. This is inefficient since it will retrieve all records on every pull operation.
```
-(void)pullData:(QSCompletionBlock)completion
{
MSQuery *query = [self.syncTable query];
// Pulls data from the remote server into the local table.
// We're pulling all items and filtering in the view
// query ID is used for incremental sync
[self.syncTable pullWithQuery:query queryId:@"allTodoItems" completion:^(NSError *error) {
[self logErrorIfNotNil:error];
// Let the caller know that we have finished
if (completion != nil) {
dispatch_async(dispatch_get_main_queue(), completion);
}
}];
}
```
>[AZURE.NOTE] To remove records from the device local store when they have been deleted in your mobile service database, enable [Soft Delete]. Otherwise, your app should periodically call `MSSyncTable.purgeWithQuery` to purge the local store.
* In **QSTodoService.m**, the methods `addItem` and `completeItem` invoke `syncData` after modifying data. In **QSTodoListViewController.m**, the method `refresh` also invokes `syncData` so that the UI displays the latest data on every refresh and at launch (`init` calls `refresh`.)
Because the app calls `syncData` whenever you modify data, the app assumes you are online whenever you edit data in the app.
## Review Core Data Model
When using the Core Data offline store, you need to define particular tables and fields in your data model. The sample app already includes a data model with the right format. In this section we walk through these tables and how they are used.
- Open **QSDataModel.xcdatamodeld**. There are four tables defined, three used by the SDK and one for the todo items themselves:
* MS_TableOperations: For tracking items to be synchronized with server
* MS_TableOperationErrors: For tracking errors that happen during offline sync
* MS_TableConfig: For tracking last updated time for last sync operation for all pull operations
* TodoItem: For storing todo items. The system columns **ms_createdAt**, **ms_updatedAt**, and **ms_version** are optional system properties.
>[AZURE.NOTE] The Mobile Services SDK reserves column names that begin with "**`ms_`**". Do not use this prefix on anything other than system columns. Otherwise, your column names will be modified when using the remote service.
- When using the offline sync feature, you must define the system tables as shown below.
### System Tables
#### MS_TableOperations
| Attribute | Type |
|-------------- | ------ |
| id (required) | Integer 64 |
| itemId | String |
| properties | Binary Data |
| table | String |
| tableKind | Integer 16 |
#### MS_TableOperationErrors
| Attribute | Type |
|-------------- | ---------- |
| id (required) | String |
| operationId | Integer 64 |
| properties | Binary Data |
| tableKind | Integer 16 |
#### MS_TableConfig
| Attribute | Type |
|-------------- | ---------- |
| id (required) | String |
| key | String |
| keyType | Integer 64 |
| table | String |
| value | String |
### Data Table
#### TodoItem
| Attribute | Type | Note |
|-------------- | ------ | -------------------------------------------------------|
| id (required) | String | primary key in remote store (required) |
| complete | Boolean | todo item field |
| text | String | todo item field |
| ms_createdAt | Date | (optional) maps to __createdAt system property |
| ms_updatedAt | Date | (optional) maps to __updatedAt system property |
| ms_version | String | (optional) used to detect conflicts, maps to __version |
## Change Sync Behavior of App
In this section, you modify the app so that it does not sync on app start, or when inserting and updating items, but only when the refresh gesture is performed.
* In **QSTodoListViewController.m**, change `viewDidLoad` to remove the call to `[self refresh]` at the end of the method. Now, the data will not be synced with the server on app start, but instead will be only stored locally.
* In **QSTodoService.m**, modify `addItem` so that it doesn't sync after the item is inserted. Remove the `self syncData` block and replace it with the following:
```
if (completion != nil) {
dispatch_async(dispatch_get_main_queue(), completion);
}
```
* Similarly, again in **QSTodoService.m**, in `completeItem`, remove the block for `self syncData` and replace with the following:
```
if (completion != nil) {
dispatch_async(dispatch_get_main_queue(), completion);
}
```
## Test App
In this section, you will turn of Wi-Fi in the simulator to create an offline scenario. When you add data items, they will be held in the local Core Data store, but not synced to the mobile service.
1. Turn off the internet connection on your Mac. Turning off WiFi in just iOS simulator may not have an effect, since the simulator may still use the host Mac's internet connection, so turn off internet for the computer itself. This simulates an offline scenario.
2. Add some todo items or complete some items. Quit the simulator (or forcibly close the app) and restart. Verify that your changes have been persisted. Notice that the data items are still displayed because they are held in the local Core Data store.
3. View the contents of the remote TodoItem table. Verify that the new items have _not_ been synced to the server.
- For the JavaScript backend, go to the [Azure classic portal](http://manage.windowsazure.com), and click the Data tab to view the contents of the `TodoItem` table.
- For the .NET backend, view the table contents either with a SQL tool such as SQL Server Management Studio, or a REST client such as Fiddler or Postman.
4. Turn on Wi-Fi in the iOS simulator. Next, perform the refresh gesture by pulling down the list of items. You will see a progress spinner and the text "Syncing...".
5. View the TodoItem data again. The new and changed TodoItems should now appear.
## Summary
In order to support the offline features of mobile services, you used the `MSSyncTable` interface and initialized `MSClient.syncContext` with a local store. In this case the local store was a Core Data-based database.
When using a Core Data local store, you define several tables with the [correct system properties][Review the Core Data model]. The normal operations for mobile services work as if the app is still connected but all the operations occur against the local store.
To synchronize the local store with the server, you used `MSSyncTable.pullWithQuery` and `MSClient.syncContext.pushWithCompletion`:
* To push changes to the server, you called `pushWithCompletion`. This method is in `MSSyncContext` instead of the sync table because it will push changes across all tables. Only records that are modified in some way locally (through CUD operations) are be sent to the server.
* To pull data from a table on the server to the app, you called `MSSyncTable.pullWithQuery`. A pull always issues a push first. This is to ensure all tables in the local store along with relationships remain consistent. `pullWithQuery` can also be used to filter the data that is stored on the client, by customizing the `query` parameter.
## Next Steps
* [Handling Conflicts with Offline Support for Mobile Services]
* [Using Soft Delete in Mobile Services][Soft Delete]
## Additional Resources
* [Cloud Cover: Offline Sync in Azure Mobile Services]
* [Azure Friday: Offline-enabled apps in Azure Mobile Services] \(note: demos are for Windows, but feature discussion applies to all platforms\)
[Get the sample app]: #get-app
[Review the Core Data model]: #review-core-data
[Review the Mobile Services sync code]: #review-sync
[Change the sync behavior of the app]: #setup-sync
[Test the app]: #test-app
[core-data-1]: ./media/mobile-services-ios-get-started-offline-data/core-data-1.png
[core-data-2]: ./media/mobile-services-ios-get-started-offline-data/core-data-2.png
[core-data-3]: ./media/mobile-services-ios-get-started-offline-data/core-data-3.png
[defining-core-data-main-screen]: ./media/mobile-services-ios-get-started-offline-data/defining-core-data-main-screen.png
[defining-core-data-model-editor]: ./media/mobile-services-ios-get-started-offline-data/defining-core-data-model-editor.png
[defining-core-data-tableoperationerrors-entity]: ./media/mobile-services-ios-get-started-offline-data/defining-core-data-tableoperationerrors-entity.png
[defining-core-data-tableoperations-entity]: ./media/mobile-services-ios-get-started-offline-data/defining-core-data-tableoperations-entity.png
[defining-core-data-tableconfig-entity]: ./media/mobile-services-ios-get-started-offline-data/defining-core-data-tableconfig-entity.png
[defining-core-data-todoitem-entity]: ./media/mobile-services-ios-get-started-offline-data/defining-core-data-todoitem-entity.png
[update-framework-1]: ./media/mobile-services-ios-get-started-offline-data/update-framework-1.png
[update-framework-2]: ./media/mobile-services-ios-get-started-offline-data/update-framework-2.png
[Core Data Model Editor Help]: https://developer.apple.com/library/mac/recipes/xcode_help-core_data_modeling_tool/Articles/about_cd_modeling_tool.html
[Creating an Outlet Connection]: https://developer.apple.com/library/mac/recipes/xcode_help-interface_builder/articles-connections_bindings/CreatingOutlet.html
[Build a User Interface]: https://developer.apple.com/library/mac/documentation/ToolsLanguages/Conceptual/Xcode_Overview/Edit_User_Interfaces/edit_user_interface.html
[Adding a Segue Between Scenes in a Storyboard]: https://developer.apple.com/library/ios/recipes/xcode_help-IB_storyboard/chapters/StoryboardSegue.html#//apple_ref/doc/uid/TP40014225-CH25-SW1
[Adding a Scene to a Storyboard]: https://developer.apple.com/library/ios/recipes/xcode_help-IB_storyboard/chapters/StoryboardScene.html
[Core Data]: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreData/cdProgrammingGuide.html
[Download the preview SDK here]: http://aka.ms/Gc6fex
[How to use the Mobile Services client library for iOS]: mobile-services-ios-how-to-use-client-library.md
[Offline iOS Sample]: https://github.com/Azure/mobile-services-samples/tree/master/TodoOffline/iOS/blog20140611
[Mobile Services sample repository on GitHub]: https://github.com/Azure/mobile-services-samples
[Get started with Mobile Services]: mobile-services-ios-get-started.md
[Handling Conflicts with Offline Support for Mobile Services]: mobile-services-ios-handling-conflicts-offline-data.md
[Soft Delete]: mobile-services-using-soft-delete.md
[Cloud Cover: Offline Sync in Azure Mobile Services]: http://channel9.msdn.com/Shows/Cloud+Cover/Episode-155-Offline-Storage-with-Donna-Malayeri
[Azure Friday: Offline-enabled apps in Azure Mobile Services]: http://azure.microsoft.com/documentation/videos/azure-mobile-services-offline-enabled-apps-with-donna-malayeri/
[Mobile Services Quick Start tutorial]: mobile-services-ios-get-started.md
================================================
FILE: docs/mobile-services-ios-get-started-users.md
================================================
# Add Authentication to Existing App
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-users.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started-users.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-users.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-get-started-users.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-windows-phone-get-started-users.md)
- [(Android | Javascript)](mobile-services-android-get-started-users.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started-users.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-users.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-users.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-users.md)
- [(HTML | Javascript)](mobile-services-html-get-started-users.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
In this tutorial, you add authentication to the [Mobile Services Quick Start tutorial] using a supported identity provider.
We recommend that you complete the [Mobile Services Quick Start tutorial] first. Alternatively, just download the Quick Start iOS project from the [Azure classic portal] click **Mobile Services** > your mobile service > the cloud sign on top left > **iOS** > **Create a New iOS App** > **Download and run your app** > **Objective-C** > **Download**. Remember to click **Create TodoItem Table** before you click **Download**, if you haven't already created the table.
## Register App for Authentication
1. In the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Dashboard**, and make a note of the **Mobile Service URL** value.
2. Register your app with one or more of the following authentication providers:
* [Google](./
mobile-services-how-to-register-google-authentication.md)
* [Facebook](./
mobile-services-how-to-register-facebook-authentication.md)
* [Twitter](./
mobile-services-how-to-register-twitter-authentication.md)
* [Microsoft](./
mobile-services-how-to-register-microsoft-authentication.md)
* [Azure Active Directory](./
mobile-services-how-to-register-active-directory-authentication.md).
Make a note of the client identity and client secret values generated by the provider. Do not distribute or share the client secret.
3. Back in the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Identity** > your identity provider settings, then enter the client ID and secret value from your provider.
You've now configured both your app and your mobile service to work with your auth provider. You may optionally repeat all these steps for each additional identity provider you'd like to support.
> [AZURE.IMPORTANT] Verify that you've set the correct redirect URI on your identity provider's developer site. As described in the linked instructions for each provider above, the redirect URI may be different for a .NET backend service vs. for a JavaScript backend service. An incorrectly configured redirect URI may result in the login screen not being displayed properly and the app malfunctioning in unexpected ways.
## Restrict Data Permissions to Authenticated Users
To secure your endpoints, you must restrict access to only authenticated clients.
1. In the [Azure classic portal](https://manage.windowsazure.com/), navigate to your mobile service, then click **Data** > your table name (**TodoItem**) > **Permissions**.
2. Set all of the table operation permissions to **Only authenticated users**.
This ensures that all operations against the table require an authenticated user, which is required for this tutorial. You can set different permissions on each operations to support your specific scenario.
## Add Authentication to App
* Open **QSTodoListViewController.m** and add the following method. Change _facebook_ to _microsoftaccount_, _twitter_, _google_, or _windowsazureactivedirectory_ if you're not using Facebook as your identity provider.
```
- (void) loginAndGetData
{
MSClient *client = self.todoService.client;
if (client.currentUser != nil) {
return;
}
[client loginWithProvider:@"facebook" controller:self animated:YES completion:^(MSUser *user, NSError *error) {
[self refresh];
}];
}
```
* Replace `[self refresh]` in `viewDidLoad` with the following:
```
[self loginAndGetData];
```
* Press **Run** to start the app, and then log in. When you are logged in, you should be able to view the Todo list and make updates.
## Store Authentication Tokens in App
The previous example contacts both the identity provider and the mobile service every time the app starts. Instead, you can cache the authorization token and try to use it first.
* The recommended way to encrypt and store authentication tokens on an iOS client is use the iOS Keychain. We'll use [SSKeychain](https://github.com/soffes/sskeychain) -- a simple wrapper around the iOS Keychain. Follow the instructions on the SSKeychain page and add it to your project. Verify that the **Enable Modules** setting is enabled in the project's **Build Settings** (section **Apple LLVM - Languages - Modules**.)
* Open **QSTodoListViewController.m** and add the following code:
```
- (void) saveAuthInfo {
[SSKeychain setPassword:self.todoService.client.currentUser.mobileServiceAuthenticationToken forService:@"AzureMobileServiceTutorial" account:self.todoService.client.currentUser.userId]
}
- (void)loadAuthInfo {
NSString *userid = [[SSKeychain accountsForService:@"AzureMobileServiceTutorial"][0] valueForKey:@"acct"];
if (userid) {
NSLog(@"userid: %@", userid);
self.todoService.client.currentUser = [[MSUser alloc] initWithUserId:userid];
self.todoService.client.currentUser.mobileServiceAuthenticationToken = [SSKeychain passwordForService:@"AzureMobileServiceTutorial" account:userid];
}
}
```
* In `loginAndGetData`, modify `loginWithProvider:controller:animated:completion:`'s completion block. Add the following line right before `[self refresh]` to store the user ID and token properties:
```
[self saveAuthInfo];
```
* Let's load the user ID and token when the app starts. In the `viewDidLoad` in **QSTodoListViewController.m**, add this right after`self.todoService` is initialized.
```
[self loadAuthInfo];
```
## Next Steps
Next, learn [how to use the user ID value to filter returned data](mobile-services-javascript-backend-service-side-authorization.md).
[Register your app for authentication and configure Mobile Services]: #register
[Restrict table permissions to authenticated users]: #permissions
[Add authentication to the app]: #add-authentication
[Next Steps]:#next-steps
[Storing authentication tokens in your app]:#store-authentication
[4]: ./media/mobile-services-ios-get-started-users/mobile-services-selection.png
[5]: ./media/mobile-services-ios-get-started-users/mobile-service-uri.png
[13]: ./media/mobile-services-ios-get-started-users/mobile-identity-tab.png
[14]: ./media/mobile-services-ios-get-started-users/mobile-portal-data-tables.png
[15]: ./media/mobile-services-ios-get-started-users/mobile-portal-change-table-perms.png
[Service-side authorization of Mobile Services users]: mobile-services-javascript-backend-service-side-authorization.md
[Submit an app page]: http://go.microsoft.com/fwlink/p/?LinkID=266582
[My Applications]: http://go.microsoft.com/fwlink/p/?LinkId=262039
[Live SDK for Windows]: http://go.microsoft.com/fwlink/p/?LinkId=262253
[Single sign-on for Windows Store apps by using Live Connect]: https://azure.microsoft.com/develop/mobile/tutorials/single-sign-on-windows-8-dotnet
[Mobile Services Quick Start tutorial]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-ios
[Get started with data]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-data-ios
[Get started with authentication]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-users-ios
[Get started with push notifications]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-push-ios
[Authorize users with scripts]: https://azure.microsoft.com/develop/mobile/tutorials/authorize-users-in-scripts-ios
[Azure classic portal]: https://manage.windowsazure.com/
================================================
FILE: docs/mobile-services-ios-get-started.md
================================================
# Get started with Mobile Services
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal JavaScript | Javascript)](mobile-services-javascript-backend-windows-store-javascript-get-started.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started.md)
- [(Android | Javascript)](mobile-services-android-get-started.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started.md)
- [(HTML | Javascript)](mobile-services-html-get-started.md)
- [(PhoneGap | Javascript)](mobile-services-javascript-backend-phonegap-get-started.md)
- [(Sencha | Javascript)](partner-sencha-mobile-services-get-started.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This tutorial shows you how to add a cloud-based backend service to an iOS app using Azure Mobile Services.
In this tutorial, you will create both a new mobile service and a simple _To do list_ app that stores app data in the new mobile service. The mobile service that you will create uses JavaScript for server-side business logic. To create a mobile service with server-side business logic in .NET, see the [.NET backend version] of this topic.
> [AZURE.NOTE] To complete this tutorial, you need an Azure account. If you don't have an account, you can sign up for an Azure trial and get [free mobile services that you can keep using even after your trial ends](https://azure.microsoft.com/pricing/details/mobile-services/). For details, see [Azure Free Trial](https://azure.microsoft.com/pricing/free-trial/?WT.mc_id=AE564AB28&returnurl=http%3A%2F%2Fazure.microsoft.com%2Fen-us%2Fdevelop%2Fmobile%2Ftutorials%2Fget-started-ios%2F%20).
## Create a new mobile service
Follow these steps to create a new mobile service.
1. Log into the [Azure classic portal](https://manage.windowsazure.com/). At the bottom of the navigation pane, click **+NEW**. Expand **Compute** and **Mobile Service**, then click **Create**.

This displays the **Create a Mobile Service** dialog.
2. In the **Create a Mobile Service** dialog, select **Create a free 20 MB SQL Database**, select **JavaScript** runtime, then type a subdomain name for the new mobile service in the **URL** textbox. Click the right arrow button to go to the next page.

This displays the **Specify database settings** page.
>[AZURE.NOTE]As part of this tutorial, you create a new SQL Database instance and server. You can reuse this new database and administer it as you would any other SQL Database instance. If you already have a database in the same region as the new mobile service, you can instead choose **Use existing Database** and then select that database. The use of a database in a different region is not recommended because of additional bandwidth costs and higher latencies.
3. In **Name**, type the name of the new database, then type **Login name**, which is the administrator login name for the new SQL Database server, type and confirm the password, and click the check button to complete the process.

You have now created a new mobile service that can be used by your mobile apps.
## Create a new iOS app
You can follow an easy Quick Start in the Azure classic portal to create a new app connected to your mobile service:
1. In the [Azure classic portal], click **Mobile Services**, and then click the mobile service that you just created.
2. In the Quick Start tab, click **iOS** under **Choose a platform** and expand **Create a new iOS app**. This displays the steps to create an iOS app connected to your mobile service.
3. Click **Create TodoItem table** to create a table to store app data.
4. Under **Download and run your app**, click **Download**. This downloads the project for the sample _To do list_ application that is connected to your mobile service, along with the Mobile Services iOS SDK. Save the compressed project file to your local computer, and make a note of where you saved it.
## Run your new iOS app
The final stage of this tutorial is to build and run your new app.
1. Browse to the location where you saved the compressed project files, expand the files on your computer, and open the project file using Xcode.
2. Press the **Run** button to build the project and start the app in the iPhone emulator.
3. In the app, type meaningful text, such as _Complete the tutorial_ and then click the plus (**+**) icon.

This sends a POST request to the new mobile service hosted in Azure. Data from the request is inserted into the TodoItem table. Items stored in the table are returned by the mobile service, and the data is displayed in the list.
Back in the [Azure classic portal], click the **DATA** tab and then click the **TodoItem** table. This lets you browse the data inserted by the app into the table.
## Next Steps
Learn how to perform additional important tasks in Mobile Services:
* [Get started with offline data sync]
Learn how to use offline data sync to make your app responsive and robust.
* [Add authentication to an existing app]
Learn how to authenticate users of your app with an identity provider.
* [Add push notifications to an existing app]
Learn how to send a very basic push notification to your app.
[Getting started with Mobile Services]:#getting-started
[Create a new mobile service]:#create-new-service
[Define the mobile service instance]:#define-mobile-service-instance
[Next Steps]:#next-steps
[6]: ./media/mobile-services-ios-get-started/mobile-portal-quickstart-ios.png
[7]: ./media/mobile-services-ios-get-started/mobile-quickstart-steps-ios.png
[8]: ./media/mobile-services-ios-get-started/mobile-xcode-project.png
[10]: ./media/mobile-services-ios-get-started/mobile-quickstart-startup-ios.png
[11]: ./media/mobile-services-ios-get-started/mobile-data-tab.png
[12]: ./media/mobile-services-ios-get-started/mobile-data-browse.png
[Get started with offline data sync]: mobile-services-ios-get-started-offline-data.md
[Add authentication to an existing app]: mobile-services-dotnet-backend-ios-get-started-users.md
[Add push notifications to an existing app]: mobile-services-dotnet-backend-ios-get-started-push.md
[Mobile Services iOS SDK]: https://go.microsoft.com/fwLink/p/?LinkID=266533
[Azure classic portal]: https://manage.windowsazure.com/
[XCode]: https://go.microsoft.com/fwLink/p/?LinkID=266532
[.NET backend version]: mobile-services-dotnet-backend-ios-get-started.md
================================================
FILE: docs/mobile-services-ios-handling-conflicts-offline-data.md
================================================
# Handling Conflicts with Offline Data Sync in Mobile Services
> [AZURE.SELECTOR-LIST (Platform | Backend)]
- [(iOS | Any)](mobile-services-ios-handling-conflicts-offline-data.md)
- [(Windows Runtime 8.1 universal C# | Any)](mobile-services-windows-store-dotnet-handling-conflicts-offline-data.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This topic shows you how to synchronize data and handle conflicts when using the offline capabilities of Azure Mobile Services. This tutorial builds on the [Get Started with Offline Data] tutorial.
>[AZURE.NOTE] To complete this tutorial, you need a Azure account. If you don't have an account, you can create a free trial account in just a couple of minutes. For details, see Azure Free Trial.
## Download iOS Project
For this tutorial, download [an updated Xcode project from Github](https://github.com/Azure/mobile-services-samples/tree/master/TodoOffline/iOS). We've used the Xcode project from the end of [Get Started with Offline Data] tutorial as a starting point, and then updated it to allow the editing of items. We've also added supporting classes and methods so we can add a conflict handler in the next section.
At the end of this tutorial, if you you run this app on two phones, change the same item on both phones locally, and push the changes back to the server, you'll allow the user on each phone to choose which version to keep:
* keep the client version (which overrides the version on the server),
* keep the server version (which updates the client local table), or
* keep neither version (cancels push and leaves the operation pending).
Now, let's add the conflict handler to enable this capability.
## Add Conflict Handler to Todo List View Controller
1. In **QSTodoListViewController.m**, edit **viewDidLoad**. Replace the call to **defaultService** with a call to **defaultServiceWithDelegate** instead:
self.todoService = [QSTodoService defaultServiceWithDelegate:self];
2. In **QSTodoListViewController.h**, add **<MSSyncContextDelegate>** to the interface declaration so we're implementing the **MSSyncContextDelegate** protocol.
@interface QSTodoListViewController : UITableViewController
3. Add the following import statement at the top of **QSTodoListViewController.m**:
#import "QSUIAlertViewWithBlock.h"
4. Finally, let's add the following two operations to **QSTodoListViewController.m** to use this helper class and prompt the user to reconcile the conflict in one of three ways.
- (void)tableOperation:(MSTableOperation *)operation onComplete:(MSSyncItemBlock)completion
{
[self doOperation:operation complete:completion];
}
-(void)doOperation:(MSTableOperation *)operation complete:(MSSyncItemBlock)completion
{
[operation executeWithCompletion:^(NSDictionary *item, NSError *error) {
NSDictionary *serverItem = [error.userInfo objectForKey:MSErrorServerItemKey];
if (error.code == MSErrorPreconditionFailed) {
QSUIAlertViewWithBlock *alert = [[QSUIAlertViewWithBlock alloc] initWithCallback:^(NSInteger buttonIndex) {
if (buttonIndex == 1) { // Client
NSMutableDictionary *adjustedItem = [operation.item mutableCopy];
[adjustedItem setValue:[serverItem objectForKey:MSSystemColumnVersion] forKey:MSSystemColumnVersion];
operation.item = adjustedItem;
[self doOperation:operation complete:completion];
return;
} else if (buttonIndex == 2) { // Server
NSDictionary *serverItem = [error.userInfo objectForKey:MSErrorServerItemKey];
completion(serverItem, nil);
} else { // Cancel
[operation cancelPush];
completion(nil, error);
}
}];
NSString *message = [NSString stringWithFormat:@"Client value: %@\nServer value: %@", operation.item[@"text"], serverItem[@"text"]];
[alert showAlertWithTitle:@"Server Conflict"
message:message
cancelButtonTitle:@"Cancel"
otherButtonTitles:[NSArray arrayWithObjects:@"Use Client", @"Use Server", nil]];
} else {
completion(item, error);
}
}];
}
## Test the App
Let's test the application with conflicts! Edit the same item in two different instances of the app running at the same time, or using the app and a REST client.
Perform the refresh gesture in the app instances by dragging from the top. Now you'll see a prompt to reconcile the conflict:
![][conflict-ui]
[Update the App Project to Allow Editing]: #update-app
[Update Todo List View Controller]: #update-list-view
[Add Todo Item View Controller]: #add-view-controller
[Add Todo Item View Controller and Segue to Storyboard]: #add-segue
[Add Item Details to Todo Item View Controller]: #add-item-details
[Add Support for Saving Edits]: #saving-edits
[Conflict Handling Problem]: #conflict-handling-problem
[Update QSTodoService to Support Conflict Handling]: #service-add-conflict-handling
[Add UI Alert View Helper to Support Conflict Handling]: #add-alert-view
[Add Conflict Handler to Todo List View Controller]: #add-conflict-handling
[Test the App]: #test-app
[add-todo-item-view-controller-3]: ./media/mobile-services-ios-handling-conflicts-offline-data/add-todo-item-view-controller-3.png
[add-todo-item-view-controller-4]: ./media/mobile-services-ios-handling-conflicts-offline-data/add-todo-item-view-controller-4.png
[add-todo-item-view-controller-5]: ./media/mobile-services-ios-handling-conflicts-offline-data/add-todo-item-view-controller-5.png
[add-todo-item-view-controller-6]: ./media/mobile-services-ios-handling-conflicts-offline-data/add-todo-item-view-controller-6.png
[todo-list-view-controller-add-segue]: ./media/mobile-services-ios-handling-conflicts-offline-data/todo-list-view-controller-add-segue.png
[update-todo-list-view-controller-2]: ./media/mobile-services-ios-handling-conflicts-offline-data/update-todo-list-view-controller-2.png
[conflict-handling-problem-1]: ./media/mobile-services-ios-handling-conflicts-offline-data/conflict-handling-problem-1.png
[conflict-ui]: ./media/mobile-services-ios-handling-conflicts-offline-data/conflict-ui.png
[Segmented Controls]: https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/UIKitUICatalog/UISegmentedControl.html
[Core Data Model Editor Help]: https://developer.apple.com/library/mac/recipes/xcode_help-core_data_modeling_tool/Articles/about_cd_modeling_tool.html
[Creating an Outlet Connection]: https://developer.apple.com/library/mac/recipes/xcode_help-interface_builder/articles-connections_bindings/CreatingOutlet.html
[Build a User Interface]: https://developer.apple.com/library/mac/documentation/ToolsLanguages/Conceptual/Xcode_Overview/Edit_User_Interfaces/edit_user_interface.html
[Adding a Segue Between Scenes in a Storyboard]: https://developer.apple.com/library/ios/recipes/xcode_help-IB_storyboard/chapters/StoryboardSegue.html#//apple_ref/doc/uid/TP40014225-CH25-SW1
[Adding a Scene to a Storyboard]: https://developer.apple.com/library/ios/recipes/xcode_help-IB_storyboard/chapters/StoryboardScene.html
[Core Data]: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreData/cdProgrammingGuide.html
[Download the preview SDK here]: http://aka.ms/Gc6fex
[How to use the Mobile Services client library for iOS]: mobile-services-ios-how-to-use-client-library.md
[Getting Started Offline iOS Sample]: https://github.com/Azure/mobile-services-samples/tree/master/TodoOffline/iOS/blog20140611
[Get Started with Offline Data]: mobile-services-ios-get-started-offline-data.md
[Get started with Mobile Services]: mobile-services-ios-get-started.md
================================================
FILE: docs/mobile-services-ios-how-to-use-client-library.md
================================================
# How to Use iOS Client Library for Azure Mobile Services
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
> [AZURE.SELECTOR]
- [Android](mobile-services-android-how-to-use-client-library.md)
- [HTML/JavaScript](mobile-services-html-how-to-use-client-library.md)
- [iOS](mobile-services-ios-how-to-use-client-library.md)
- [Managed (Windows/Xamarin)](mobile-services-dotnet-how-to-use-client-library.md)
This guide teaches you to perform common scenarios using the Azure Mobile Services [iOS SDK]. If you are new to Mobile Services, first complete [Mobile Services Quick Start] to configure your account, create a table, and create a mobile service.
> [AZURE.NOTE] This guide uses the latest [iOS Mobile Services SDK](https://go.microsoft.com/fwLink/?LinkID=266533&clcid=0x409). If your project uses an older version of the SDK, first upgrade the framework in Xcode.
## What is Mobile Services
Azure Mobile Services is a highly scalable mobile application development platform that lets you add enhanced functionality to your mobile device apps by using Azure.
With Mobile Services you can:
+ **Build native and cross platform apps** - Connect your iOS, Android, Windows, or cross-platform Xamarin or Cordova (Phonegap) apps to your backend mobile service using native SDKs.
+ **Send push notifications to your users** - Send push notifications to your users of your app.
+ **Authenticate your users** - Leverage popular identity providers like Facebook and Twitter to authenticate your app users.
+ **Store data in the cloud** - Store user data in a SQL Database (by default) or in Mongo DB, DocumentDB, Azure Tables, or Azure Blobs.
+ **Build offline-ready apps with sync** - Make your apps work offline and use Mobile Services to sync data in the background.
+ **Monitor and scale your apps** - Monitor app usage and scale your backend as demand grows.
## Mobile Services Concepts
The following are important features and concepts in the Mobile Services:
+ **Application key:** a unique value that is used to limit access to your mobile service from random clients; this "key" is not a security token and is not used to authenticate users of your app.
+ **Backend:** the mobile service instance that supports your app. A mobile service is implemented either as an ASP.NET Web API project (*.NET backend* ) or as a Node.js project (*JavaScript backend*).
+ **Identity provider:** an external service, trusted by Mobile Services, that authenticates your app's users. Supported providers include: Facebook, Twitter, Google, Microsoft Account, and Azure Active Directory.
+ **Push notification:** Service-initiated message that is sent to a registered device or user using Azure Notification Hubs.
+ **Scale:** The ability to add, for an additional cost, more processing power, performance, and storage as your app becomes more popular.
+ **Scheduled job:** Custom code that is run either on a pre-determined schedule or on-demand.
For more information, see [Mobile Services Concepts](./
mobile-services-concepts-links.md).
## Setup and Prerequisites
This guide assumes that you have created a mobile service with a table. For more information see [Create a table], or reuse the `TodoItem` table created in [Mobile Services Quick Start]. This guide assumes that the table has the same schema as the tables in those tutorials. This guide also assumes that your Xcode references `WindowsAzureMobileServices.framework` and imports `WindowsAzureMobileServices/WindowsAzureMobileServices.h`.
## How to: Create Mobile Services Client
To access an Azure mobile service in your project, create an `MSClient` client object. Replace `AppUrl` and `AppKey` with the mobile service URL and the application key Dashboard values, respectively.
```
MSClient *client = [MSClient clientWithApplicationURLString:@"AppUrl" applicationKey:@"AppKey"];
```
## How to: Create Table Reference
To access or update data for your Azure mobile service, create a reference to the table. Replace `TodoItem` with the name of your table.
```
MSTable *table = [client tableWithName:@"TodoItem"];
```
## How to: Query Data
To create a database query, query the `MSTable` object. The following query gets all the items in `TodoItem` and logs the text of each item.
```
[table readWithCompletion:^(MSQueryResult *result, NSError *error) {
if(error) { // error is nil if no error occured
NSLog(@"ERROR %@", error);
} else {
for(NSDictionary *item in result.items) { // items is NSArray of records that match query
NSLog(@"Todo Item: %@", [item objectForKey:@"text"]);
}
}
}];
```
## How to: Filter Returned Data
To filter results, there are many available options.
To filter using a predicate, use an `NSPredicate` and `readWithPredicate`. The following filters returned data to find only incomplete Todo items.
```
// Create a predicate that finds items where complete is false
NSPredicate * predicate = [NSPredicate predicateWithFormat:@"complete == NO"];
// Query the TodoItem table and update the items property with the results from the service
[table readWithPredicate:predicate completion:^(MSQueryResult *result, NSError *error) {
if(error) {
NSLog(@"ERROR %@", error);
} else {
for(NSDictionary *item in result.items) {
NSLog(@"Todo Item: %@", [item objectForKey:@"text"]);
}
}
}];
```
## How to: Use MSQuery
To perform a complex query (including sorting and paging), create an `MSQuery` object, directly or by using a predicate:
```
MSQuery *query = [table query];
MSQuery *query = [table queryWithPredicate: [NSPredicate predicateWithFormat:@"complete == NO"]];
```
`MSQuery` lets you control several query behaviors, including the following. Execute an `MSQuery` query by calling `readWithCompletion` on it, as shown in the next example.
* Specify order of results
* Limit which fields to return
* Limit how many records to return
* Specify total count in response
* Specify custom query string parameters in request
* Apply additional functions
## How to: Sort Data with MSQuery
To sort results, let's look at an example. To first ascendingly by field `text` and then descendingly by field `completion`, invoke `MSQuery` like so:
```
[query orderByAscending:@"text"];
[query orderByDescending:@"complete"];
[query readWithCompletion:^(MSQueryResult *result, NSError *error) {
if(error) {
NSLog(@"ERROR %@", error);
} else {
for(NSDictionary *item in result.items) {
NSLog(@"Todo Item: %@", [item objectForKey:@"text"]);
}
}
}];
```
## How to: Return Data in Pages with MSQuery
Mobile Services limits the amount of records that are returned in a single response. To control the number of records displayed to your users you must implement a paging system. Paging is performed by using the following three properties of the **MSQuery** object:
```
+ `BOOL includeTotalCount`
+ `NSInteger fetchLimit`
+ `NSInteger fetchOffset`
```
In the following example, a simple function requests 5 records from the server and then appends them to the local collection of previously loaded records:
```
// Create and initialize these properties
@property (nonatomic, strong) NSMutableArray *loadedItems; // Init via [[NSMutableArray alloc] init]
@property (nonatomic) BOOL moreResults;
```
```
-(void)loadResults
{
MSQuery *query = [self.table query];
query.includeTotalCount = YES;
query.fetchLimit = 5;
query.fetchOffset = self.loadedItems.count;
[query readWithCompletion:^(MSQueryResult *result, NSError *error) {
if(!error) {
// Add the items to our local copy
[self.loadedItems addObjectsFromArray:result.items];
// Set a flag to keep track if there are any additional records we need to load
self.moreResults = (self.loadedItems.count <= result.totalCount);
}
}];
}
```
## How to: Limit Fields and Expand Query String Parameters with MSQuery
To limit fields to be returned in a query, specify the names of the fields in the **selectFields** property. This returns only the text and completed fields:
```
query.selectFields = @[@"text", @"completed"];
```
To include additional query string parameters in the server request (for example, because a custom server-side script uses them), populate `query.parameters` like so:
```
query.parameters = @{
@"myKey1" : @"value1",
@"myKey2" : @"value2",
};
```
## How to: Insert Data
To insert a new table row, create a new `NSDictionary` and invoke `table insert`. Mobile Services automatically generates new columns based on the `NSDictionary` if [Dynamic Schema] is not disabled.
If `id` is not provided, the backend automatically generates a new unique ID. Provide your own `id` to use email addresses, usernames, or your own custom values as ID. Providing your own ID may ease joins and business-oriented database logic.
```
NSDictionary *newItem = @{@"id": @"custom-id", @"text": @"my new item", @"complete" : @NO};
[self.table insert:newItem completion:^(NSDictionary *result, NSError *error) {
// The result contains the new item that was inserted,
// depending on your server scripts it may have additional or modified
// data compared to what was passed to the server.
if(error) {
NSLog(@"ERROR %@", error);
} else {
NSLog(@"Todo Item: %@", [result objectForKey:@"text"]);
}
}];
```
## How to: Modify Data
To update an existing row, modify an item and call `update`:
```
NSMutableDictionary *newItem = [oldItem mutableCopy]; // oldItem is NSDictionary
[newItem setValue:@"Updated text" forKey:@"text"];
[self.table update:newItem completion:^(NSDictionary *item, NSError *error) {
// Handle error or perform additional logic as needed
}];
```
Alternatively, supply the row ID and the updated field:
```
[self.table update:@{@"id":@"37BBF396-11F0-4B39-85C8-B319C729AF6D", @"Complete":@YES} completion:^(NSDictionary *item, NSError *error) {
// Handle error or perform additional logic as needed
}];
```
At minimum, the `id` attribute must be set when making updates.
## How to: Delete Data
To delete an item, invoke `delete` with the item:
```
[self.table delete:item completion:^(id itemId, NSError *error) {
// Handle error or perform additional logic as needed
}];
```
Alternatively, delete by providing a row ID:
```
[self.table deleteWithId:@"37BBF396-11F0-4B39-85C8-B319C729AF6D" completion:^(id itemId, NSError *error) {
// Handle error or perform additional logic as needed
}];
```
At minimum, the `id` attribute must be set when making deletes.
## How to: Call a custom API
A custom API enables you to define custom endpoints that expose server functionality that does not map to an insert, update, delete, or read operation. By using a custom API, you can have more control over messaging, including reading and setting HTTP message headers and defining a message body format other than JSON. For an example of how to create a custom API in your mobile service, see [How to: define a custom API endpoint](mobile-services-dotnet-backend-define-custom-api.md).
### Call custom API from iOS app
To call this custom API from an iOS client, use the `MSClient invokeAPI` method. There are two versions of this method, one for JSON-formatted requests, and one for any data type:
/// Invokes a user-defined API of the Mobile Service. The HTTP request and
/// response content will be treated as JSON.
-(void)invokeAPI:(NSString *)APIName
body:(id)body
HTTPMethod:(NSString *)method
parameters:(NSDictionary *)parameters
headers:(NSDictionary *)headers
completion:(MSAPIBlock)completion;
/// Invokes a user-defined API of the Mobile Service. The HTTP request and
/// response content can be of any media type.
-(void)invokeAPI:(NSString *)APIName
data:(NSData *)data
HTTPMethod:(NSString *)method
parameters:(NSDictionary *)parameters
headers:(NSDictionary *)headers
completion:(MSAPIDataBlock)completion;
For example, to send a JSON request to a custom API named "sendEmail", pass an `NSDictionary` for the request parameters:
NSDictionary *emailHeader = @{ @"to": @"email.com", @"subject" : @"value" };
[self.client invokeAPI:@"sendEmail"
body:emailBody
HTTPMethod:@"POST"
parameters:emailHeader
headers:nil
completion:completion ];
If you need the data returned then you can use something like this:
[self.client invokeAPI:apiName
body:yourBody
HTTPMethod:httpMethod
parameters:parameters
headers:headers
completion: ^(NSData *result,
NSHTTPURLResponse *response,
NSError *error){
// error is nil if no error occured
if(error) {
NSLog(@"ERROR %@", error);
} else {
// do something with the result
}
}];
## How to: Authenticate Users
Azure Mobile Services supports various identity providers. For a basic tutorial, see [Authentication].
Azure Mobile Services supports two authentication workflows:
- **Server-managed Login**: Azure Mobile Services manages the login process on behalf of your app. It displays a provider-specific login page and authenticates with the chosen provider.
- **Client-managed Login**: The _app_ requests a token from the identity provider and presents this token to Azure Mobile Services for authentication.
When authentication succeeds, you get back a user object with a user ID value and the auth token. To use this user ID to authorize users, see [Service-side Authorization]. To restrict table access to only authenticated users, see [Permissions].
### Server-managed Login
Here is how you can add server-managed login to the [Mobile Services Quick Start] project; you may use similar code for your other projects. For more information and to see an end-to-end example in action, see [Authentication].
* Open **QSTodoListViewController.m** and add the following method. Change _facebook_ to _microsoftaccount_, _twitter_, _google_, or _windowsazureactivedirectory_ if you're not using Facebook as your identity provider.
```
- (void) loginAndGetData
{
MSClient *client = self.todoService.client;
if (client.currentUser != nil) {
return;
}
[client loginWithProvider:@"facebook" controller:self animated:YES completion:^(MSUser *user, NSError *error) {
[self refresh];
}];
}
```
* Replace `[self refresh]` in `viewDidLoad` with the following:
```
[self loginAndGetData];
```
* Press **Run** to start the app, and then log in. When you are logged in, you should be able to view the Todo list and make updates.
### Client-managed Login (Single Sign-on)
You may do the login process outside the Mobile Services client, either to enable single sign-on or if your app contacts the identity provider directly. In such cases, you can log in to Mobile Services by providing a token obtained independently from a supported identity provider.
The following example uses the [Live Connect SDK] to enable single sign-on for iOS apps. It assumes that you have a **LiveConnectClient** instance named `liveClient` in the controller and the user is logged in.
```
[client loginWithProvider:@"microsoftaccount"
token:@{@"authenticationToken" : self.liveClient.session.authenticationToken}
completion:^(MSUser *user, NSError *error) {
// Handle success and errors
}];
```
## How to: Cache Authentication Tokens
Let's see how you may cache tokens in the [Mobile Services Quick Start] project; you may apply similar steps to any project.
* The recommended way to encrypt and store authentication tokens on an iOS client is use the iOS Keychain. We'll use [SSKeychain](https://github.com/soffes/sskeychain) -- a simple wrapper around the iOS Keychain. Follow the instructions on the SSKeychain page and add it to your project. Verify that the **Enable Modules** setting is enabled in the project's **Build Settings** (section **Apple LLVM - Languages - Modules**.)
## How to: Handle Errors
When you call a mobile service, the completion block contains an `NSError *error` parameter. When an error occurs, this parameter is non-nil. In your code, you should check this parameter and handle the error as needed.
The file [``](https://github.com/Azure/azure-mobile-services/blob/master/sdk/iOS/src/MSError.h) defines the constants `MSErrorResponseKey`, `MSErrorRequestKey`, and `MSErrorServerItemKey` to get more data related to the error. In addition, the file defines constants for each error code. For an example on how to use these constants, see [Conflict-Handler] for its usage of `MSErrorServerItemKey` and `MSErrorPreconditionFailed`.
[What is Mobile Services]: #what-is
[Concepts]: #concepts
[Setup and Prerequisites]: #Setup
[How to: Create the Mobile Services client]: #create-client
[How to: Create a table reference]: #table-reference
[How to: Query data from a mobile service]: #querying
[Filter returned data]: #filtering
[Sort returned data]: #sorting
[Return data in pages]: #paging
[Select specific columns]: #selecting
[How to: Bind data to the user interface]: #binding
[How to: Insert data into a mobile service]: #inserting
[How to: Modify data in a mobile service]: #modifying
[How to: Authenticate users]: #authentication
[Cache authentication tokens]: #caching-tokens
[How to: Upload images and large files]: #blobs
[How to: Handle errors]: #errors
[How to: Design unit tests]: #unit-testing
[How to: Customize the client]: #customizing
[Customize request headers]: #custom-headers
[Customize data type serialization]: #custom-serialization
[Next Steps]: #next-steps
[How to: Use MSQuery]: #query-object
[Mobile Services Quick Start]: mobile-services-ios-get-started.md
[Get started with Mobile Services]: mobile-services-ios-get-started.md
[Mobile Services SDK]: https://go.microsoft.com/fwLink/p/?LinkID=266533
[Authentication]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-users-ios
[iOS SDK]: https://developer.apple.com/xcode
[Handling Expired Tokens]: http://go.microsoft.com/fwlink/p/?LinkId=301955
[Live Connect SDK]: http://go.microsoft.com/fwlink/p/?LinkId=301960
[Permissions]: http://msdn.microsoft.com/library/windowsazure/jj193161.aspx
[Service-side Authorization]: mobile-services-javascript-backend-service-side-authorization.md
[Dynamic Schema]: http://go.microsoft.com/fwlink/p/?LinkId=296271
[Create a table]: http://msdn.microsoft.com/library/windowsazure/jj193162.aspx
[NSDictionary object]: http://go.microsoft.com/fwlink/p/?LinkId=301965
[ASCII control codes C0 and C1]: http://en.wikipedia.org/wiki/Data_link_escape_character#C1_set
[CLI to manage Mobile Services tables]: https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-command-line-tools/#Mobile_Tables
[Conflict-Handler]: mobile-services-ios-handling-conflicts-offline-data.md#add-conflict-handling
================================================
FILE: docs/mobile-services-javascript-backend-android-get-started-push.md
================================================
# Add push notifications to your Mobile Services Android app
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-push.md)
- [(iOS | JavaScript)](mobile-services-javascript-backend-ios-get-started-push.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-push.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-get-started-push.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-javascript-backend-windows-phone-get-started-push.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started-push.md)
- [(Android | Javascript)](mobile-services-javascript-backend-android-get-started-push.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-push.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-push.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-push.md)
- [(Xamarin.Forms | JavaScript)](partner-xamarin-mobile-services-xamarin-forms-get-started-push.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
## Summary
This topic shows how to use Azure Mobile Services to send push notifications to your Android app using Google Cloud Messaging ("GCM"). You will add push notifications to the quickstart project that is a prerequisite for this tutorial. Push notifications are enabled by using the Azure Notification Hub that is included in your mobile service. When complete, your mobile service will send a push notification each time a record is inserted.
## Prerequisites
This tutorial is based on the code you download in the Mobile Services quickstart. Before you start this tutorial, you must first complete either [Get started with Mobile Services] or [Add Mobile Services to an existing app].
> [AZURE.IMPORTANT] If you completed the quickstart tutorial prior to the release of Azure Mobile Services Android SDK 2.0, you must re-do it, because the SDK is not backwards compatible. To verify the version, check the **dependencies** section of your project's **build.gradle** file.
## Sample code
To see the completed source code go [here](https://github.com/Azure/mobile-services-samples/tree/master/GettingStartedWithPush).
## Enable Google Cloud Messaging
1. Navigate to the [Google Cloud Console](https://console.developers.google.com/project), sign in with your Google account credentials.
2. Click **Create Project**, type a project name, then click **Create**. If requested, carry out the SMS Verification, and click **Create** again.

Type in your new **Project name** and click **Create project**.
3. Click the **Utilities and More** button and then click **Project Information**. Make a note of the **Project Number**. You will need to set this value as the `SenderId` variable in the client app.

4. In the project dashboard, under **Mobile APIs**, click **Google Cloud Messaging**, then on the next page click **Enable API** and accept the terms of service.


5. In the project dashboard, Click **Credentials** > **Create Credential** > **API Key**.

6. In **Create a new key**, click **Server key**, type a name for your key, then click **Create**.
7. Make a note of the **API KEY** value.
You will use this API key value to enable Azure to authenticate with GCM and send push notifications on behalf of your app.
## Configure Mobile Services to send push requests
1. Log on to the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services**, and then click your app.
2. Click the **Push** tab, enter the **API Key** value obtained from GCM in the previous procedure, then click **Save**.

>[AZURE.NOTE]When you set your GCM credentials for enhanced push notifications in the Push tab in the portal, they are shared with Notification Hubs to configure the notification hub with your app.
Both your mobile service and your app are now configured to work with GCM and Notification Hubs.
## Add push notifications to your app
Your next step is to install Google Play services. Google Cloud Messaging has some minimum API level requirements for development and testing, which the **minSdkVersion** property in the Manifest must conform to.
If you will be testing with an older device, then consult [Set Up Google Play Services SDK] to determine how low you can set this value, and set it appropriately.
### Add Google Play Services to the project
1. Open the Android SDK Manager by clicking the icon on the toolbar of Android Studio or by clicking **Tools** -> **Android** -> **SDK Manager** on the menu. Locate the target version of the Android SDK that is used in your project , open it, and choose **Google APIs**, if it is not already installed.
2. Scroll down to **Extras**, expand it, and choose **Google Play Services**, as shown below. Click **Install Packages**. Note the SDK path, for use in the following step.

3. Open the **build.gradle** file in the app directory.

4. Add this line under *dependencies*:
compile 'com.google.android.gms:play-services-gcm:8.4.0'
5. Under *defaultConfig*, change *minSdkVersion* to 9.
6. Click the **Sync Project with Gradle Files** icon in the tool bar.
7. Open **AndroidManifest.xml** and add this tag to the *application* tag.
### Add code
1. In your **app** project, open the file `AndroidManifest.xml`. In the code in the next two steps, replace _`**my_app_package**`_ with the name of the app package for your project, which is the value of the `package` attribute of the `manifest` tag.
2. Add the following new permissions after the existing `uses-permission` element:
3. Add the following code after the `application` opening tag:
4. Add this line under *dependencies* in the **build.gradle** file in the app directory and re-sync gradle with the project:
compile(group: 'com.microsoft.azure', name: 'azure-notifications-handler', version: '1.0.1', ext: 'jar')
5. Open the file *ToDoItemActivity.java*, and add the following import statement:
import com.microsoft.windowsazure.notifications.NotificationsManager;
6. Add the following private variable to the class: replace _``_ with the Project Number assigned by Google to your app in the preceding procedure:
public static final String SENDER_ID = "";
7. Change the definition of the *MobileServiceClient* from **private** to **public static**, so it now looks like this:
public static MobileServiceClient mClient;
8. Next we need to add a new class to handle notifications. In the Project Explorer, open the **src** => **main** => **java** nodes, and right-click the package name node: click **New**, then click **Java Class**.
9. In **Name** type `MyHandler`, then click **OK**.

10. In the MyHandler file, replace the class declaration with
public class MyHandler extends NotificationsHandler {
11. Add the following import statements for the `MyHandler` class:
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
12. Next add the following members for the `MyHandler` class:
public static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
Context ctx;
13. In the `MyHandler` class, add the following code to override the **onRegistered** method, which registers your device with the mobile service Notification Hub.
@Override
public void onRegistered(Context context, final String gcmRegistrationId) {
super.onRegistered(context, gcmRegistrationId);
new AsyncTask() {
protected Void doInBackground(Void... params) {
try {
ToDoActivity.mClient.getPush().register(gcmRegistrationId, null);
return null;
}
catch(Exception e) {
// handle error
}
return null;
}
}.execute();
}
14. In the `MyHandler` class, add the following code to override the **onReceive** method, which causes the notification to display when it is received.
@Override
public void onReceive(Context context, Bundle bundle) {
ctx = context;
String nhMessage = bundle.getString("message");
sendNotification(nhMessage);
}
private void sendNotification(String msg) {
mNotificationManager = (NotificationManager)
ctx.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(ctx, 0,
new Intent(ctx, ToDoActivity.class), 0);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(ctx)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Notification Hub Demo")
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(msg))
.setContentText(msg);
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
15. Back in the TodoActivity.java file, update the **onCreate** method of the *ToDoActivity* class to register the notification handler class. Make sure to add this code after the *MobileServiceClient* is instantiated.
NotificationsManager.handleNotifications(this, SENDER_ID, MyHandler.class);
Your app is now updated to support push notifications.
[Mobile Services Android SDK]: http://aka.ms/Iajk6q
## Update the registered insert script in the Azure classic portal
1. In the [Azure classic portal](https://manage.windowsazure.com/), click the **Data** tab and then click the **TodoItem** table.
2. In **todoitem**, click the **Script** tab and select **Insert**.
This displays the function that is invoked when an insert occurs in the **TodoItem** table.
3. Replace the insert function with the following code, and then click **Save**:
function insert(item, user, request) {
// Define a simple payload for a GCM notification.
var payload = {
"data": {
"message": item.text
}
};
request.execute({
success: function() {
// If the insert succeeds, send a notification.
push.gcm.send(null, payload, {
success: function(pushResponse) {
console.log("Sent push:", pushResponse, payload);
request.respond();
},
error: function (pushResponse) {
console.log("Error Sending push:", pushResponse);
request.respond(500, { error: pushResponse });
}
});
},
error: function(err) {
console.log("request.execute error", err)
request.respond();
}
});
}
This registers a new insert script, which uses the [gcm object](http://go.microsoft.com/fwlink/p/?LinkId=282645) to send a push notification to all registered devices after the insert succeeds.
## Test push notifications in your app
You can test the app by directly attaching an Android phone with a USB cable, or by using a virtual device in the emulator.
### Setting up the Android emulator for testing
When you run this app in the emulator, make sure that you use an Android Virtual Device (AVD) that supports Google APIs.
1. From the right end of the toolbar, select the Android Virtual Device Manager, select your device, click the edit icon on the right.

2. Select **Change** on the device description line, select **Google APIs**, then click OK.

This targets the AVD to use Google APIs.
### Running the test
1. From the **Run** menu item, click **Run app** to start the app.
2. In the app, type meaningful text, such as _A new Mobile Services task_ and then click the **Add** button.

3. Swipe down from the top of the screen to open the device's Notification Drawer to see the notification.
You have successfully completed this tutorial.
## Troubleshooting
### Verify Android SDK Version
Because of ongoing development, the Android SDK version installed in Android Studio might not match the version in the code. The Android SDK referenced in this tutorial is version 21, the latest at the time of writing. The version number may increase as new releases of the SDK appear, and we recomend using the latest version available.
Two symptoms of version mismatch are:
1. When you Build or Rebuild the project, you may get Gradle error messages like "**failed to find target Google Inc.:Google APIs:n**".
2. Standard Android objects in code that should resolve based on `import` statements may be generating error messages.
If either of these appear, the version of the Android SDK installed in Android Studio might not match the SDK target of the downloaded project. To verify the version, make the following changes:
1. In Android Studio, click **Tools** => **Android** => **SDK Manager**. If you have not installed the latest version of the SDK Platform, then click to install it. Make a note of the version number.
2. In the Project Explorer tab, under **Gradle Scripts**, open the file **build.gradle (modeule: app)**. Ensure that the **compileSdkVersion** and **buildToolsVersion** are set to the latest SDK version installed. The tags might look like this:
compileSdkVersion 'Google Inc.:Google APIs:21'
buildToolsVersion "21.1.2"
3. In the Android Studio Project Explorer right-click the project node, choose **Properties**, and in the left column choose **Android**. Ensure that the **Project Build Target** is set to the same SDK version as the **targetSdkVersion**.
4. In Android Studio, the manifest file is no longer used to specify the target SDK and minimum SDK version, unlike the case with Eclipse.
## Next steps
Learn more about Mobile Services and Notification Hubs in the following topics:
* [Get started with authentication]
Learn how to authenticate users of your app with different account types using mobile services.
* [What are Notification Hubs?]
Learn more about how Notification Hubs works to deliver notifications to your apps across all major client platforms.
* [Debug Notification Hubs applications](http://go.microsoft.com/fwlink/p/?linkid=386630)
Get guidance troubleshooting and debugging Notification Hubs solutions.
* [How to use the Android client library for Mobile Services]
Learn more about how to use Mobile Services with Android.
* [Mobile Services server script reference]
Learn more about how to implement business logic in your mobile service.
[Register your app for push notifications and configure Mobile Services]: #register
[Update the generated push notification code]: #update-scripts
[Insert data to receive notifications]: #test
[Next Steps]:#next-steps
[13]: ./media/mobile-services-windows-store-javascript-get-started-push/mobile-quickstart-push1.png
[14]: ./media/mobile-services-windows-store-javascript-get-started-push/mobile-quickstart-push2.png
[Submit an app page]: http://go.microsoft.com/fwlink/p/?LinkID=266582
[My Applications]: http://go.microsoft.com/fwlink/p/?LinkId=262039
[Get started with Mobile Services]: mobile-services-android-get-started.md
[Get started with authentication]: mobile-services-android-get-started-users.md
[Get started with push notifications]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-push-js
[Push notifications to app users]: https://azure.microsoft.com/develop/mobile/tutorials/push-notifications-to-users-js
[Authorize users with scripts]: https://azure.microsoft.com/develop/mobile/tutorials/authorize-users-in-scripts-js
[JavaScript and HTML]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-push-js
[Set Up Google Play Services SDK]: http://go.microsoft.com/fwlink/?LinkId=389801
[Azure classic portal]: https://manage.windowsazure.com/
[How to use the Android client library for Mobile Services]: mobile-services-android-how-to-use-client-library.md
[gcm object]: http://go.microsoft.com/fwlink/p/?LinkId=282645
[Mobile Services server script reference]: http://go.microsoft.com/fwlink/?LinkId=262293
[What are Notification Hubs?]: https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-push-notification-overview/
[Send broadcast notifications to subscribers]: https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-aspnet-backend-android-xplat-segmented-gcm-push-notification/
[Send template-based notifications to subscribers]: https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-aspnet-backend-android-xplat-segmented-gcm-push-notification/
================================================
FILE: docs/mobile-services-javascript-backend-define-custom-api.md
================================================
# How to: define a custom API endpoint in a JavaScript backend mobile service
> [AZURE.SELECTOR]
- [JavaScript backend](./mobile-services-javascript-backend-define-custom-api.md)
- [.NET backend](./mobile-services-dotnet-backend-define-custom-api.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This topic shows you how to define a custom API endpoint in a JavaScript backend mobile service. A custom API lets you define custom endpoints with server functionality, but it does not map to a database insert, update, delete, or read operation. By using a custom API, you have more control over messaging, including HTTP headers and body format.
1. Log into the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services**, and then select your mobile service.
2. Click the **API** tab, and then click **Create**. This displays the **Create a new custom API** dialog.
3. Type _completeall_ in **API name**, and then click the check button to create the new API.
> [AZURE.TIP] With default permissions, anyone with the app key may call the custom API. However, the application key is not considered a secure credential because it may not be distributed or stored securely. Consider restricting access to only authenticated users for additional security.
4. Click on **completeall** in the API table.
5. Click the **Script** tab, replace the existing code with the following code, then click **Save**. This code uses the [mssql object] to access the **todoitem** table directly to set the `complete` flag on all items. Because the **exports.post** function is used, clients send a POST request to perform the operation. The number of changed rows is returned to the client as an integer value.
exports.post = function(request, response) {
var mssql = request.service.mssql;
var sql = "UPDATE todoitem SET complete = 1 " +
"WHERE complete = 0; SELECT @@ROWCOUNT as count";
mssql.query(sql, {
success: function(results) {
if(results.length == 1)
response.send(200, results[0]);
}
})
};
> [AZURE.NOTE] The [request](http://msdn.microsoft.com/library/windowsazure/jj554218.aspx) and [response](http://msdn.microsoft.com/library/windowsazure/dn303373.aspx) object supplied to custom API functions are implemented by the [Express.js library](http://go.microsoft.com/fwlink/p/?LinkId=309046).
[mssql object]: http://msdn.microsoft.com/library/windowsazure/jj554212.aspx
For information on how to invoke a custom API in your app using a Mobile Services client library, see [Call a custom API](mobile-services-windows-dotnet-how-to-use-client-library.md#custom-api) in the client SDK reference.
================================================
FILE: docs/mobile-services-javascript-backend-ios-get-started-push.md
================================================
# Add Push Notifications to iOS App and JavaScript Backend
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-push.md)
- [(iOS | JavaScript)](mobile-services-javascript-backend-ios-get-started-push.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-push.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-get-started-push.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-javascript-backend-windows-phone-get-started-push.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started-push.md)
- [(Android | Javascript)](mobile-services-javascript-backend-android-get-started-push.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-push.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-push.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-push.md)
- [(Xamarin.Forms | JavaScript)](partner-xamarin-mobile-services-xamarin-forms-get-started-push.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This topic shows you how to add push notifications to the [quickstart project](mobile-services-ios-get-started.md), so that your mobile service sends a push notification each time a record is inserted. You must complete [Get Started with Mobile Services] first.
> [AZURE.NOTE] The [iOS simulator does not support push notifications](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/iOS_Simulator_Guide/TestingontheiOSSimulator.html), so you must use a physical iOS device. You'll also need to sign up for a paid [Apple Developer Program membership](https://developer.apple.com/programs/ios/).
* [Register an App ID for your app](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/MaintainingProfiles/MaintainingProfiles.html#//apple_ref/doc/uid/TP40012582-CH30-SW991). Create an explicit App ID (not a wildcard App ID) and for **Bundle ID**, use the exact **Bundle ID** that is in your Xcode quickstart project. It is also crucial that you check the **Push Notifications** option.
* Next, [configuring push notifications](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/AddingCapabilities/AddingCapabilities.html#//apple_ref/doc/uid/TP40012582-CH26-SW6). You may create either a "Development" or "Distribution" SSL certificate (remember to select the corresponding option in the Azure portal later.)
## Configure Azure to Send Push Notifications
* Follow the steps at [Installing a Client SSL Signing Identity on the Server](https://developer.apple.com/library/prerelease/ios/documentation/IDEs/Conceptual/AppDistributionGuide/AddingCapabilities/AddingCapabilities.html#//apple_ref/doc/uid/TP40012582-CH26-SW16) to export the certificate you downloaded in the previous step to a .p12 file.
* In the Azure classic portal, click **Mobile Services** > your app > the **Push** tab > **apple push notification settings** > "**Upload**. Upload the .p12 file, making sure that the correct **Mode** is selected (either Sandbox or Production, corresponding to whether the client SSL certificate you generated was Development or Distribution.) Your mobile service is now configured to work with push notifications on iOS!
## Update Backend Script to Send Push Notifications
* In the [Azure classic portal], click the **Data** tab and then click **TodoItem**. In **TodoItem**, click the **Script** tab and select **Insert**. This displays the function that is invoked when an insert occurs in the **TodoItem** table.
* Replace the insert function with the following code, and then click **Save**. This registers a new insert script, which uses the [apns object] to send a push notification (the inserted text) to the device provided in the insert request. This script delays sending the notification to give you time to close the app to receive a push notification.
```
function insert(item, user, request) {
request.execute();
// Set timeout to delay the notification, to provide time for the
// app to be closed on the device to demonstrate push notifications
setTimeout(function() {
push.apns.send(null, {
alert: "Alert: " + item.text,
payload: {
inAppMessage: "Hey, a new item arrived: '" + item.text + "'"
}
});
}, 2500);
}
```
## Add Push Notifications to App
* In QSAppDelegate.m, import the iOS SDK and QSTodoService.h:
```
#import
#import "QSTodoService.h"
```
* In `didFinishLaunchingWithOptions` in QSAppDelegate.m, insert the following lines right before `return YES;`:
```
UIUserNotificationSettings* notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
```
* In QSAppDelegate.m, add the following handler methods. Your app is now updated to support push notifications.
```
// Registration with APNs is successful
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
QSTodoService *todoService = [QSTodoService defaultService];
MSClient *client = todoService.client;
[client.push registerNativeWithDeviceToken:deviceToken tags:nil completion:^(NSError *error) {
if (error != nil) {
NSLog(@"Error registering for notifications: %@", error);
}
}];
}
// Handle any failure to register
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:
(NSError *)error {
NSLog(@"Failed to register for remote notifications: %@", error);
}
// Use userInfo in the payload to display a UIAlertView.
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo {
NSLog(@"%@", userInfo);
NSDictionary *apsPayload = userInfo[@"aps"];
NSString *alertString = apsPayload[@"alert"];
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:@"Notification"
message:alertString
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
}
```
* In Xcode, press **Run** and start the app on an iOS device (not the simulator.) Click **OK** to accept push notifications; this request occurs the first time the app runs.
* In the app, add a new item and click **+**.
* Verify that a notification is received, then click **OK** to dismiss the notification. You have now successfully completed this tutorial.

[5]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-step5.png
[6]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-step6.png
[7]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-step7.png
[9]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-step9.png
[10]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-step10.png
[17]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-step17.png
[18]: ./media/mobile-services-ios-get-started-push/mobile-services-selection.png
[19]: ./media/mobile-services-ios-get-started-push/mobile-push-tab-ios.png
[20]: ./media/mobile-services-ios-get-started-push/mobile-push-tab-ios-upload.png
[21]: ./media/mobile-services-ios-get-started-push/mobile-portal-data-tables.png
[22]: ./media/mobile-services-ios-get-started-push/mobile-insert-script-push2.png
[23]: ./media/mobile-services-ios-get-started-push/mobile-quickstart-push1-ios.png
[24]: ./media/mobile-services-ios-get-started-push/mobile-quickstart-push2-ios.png
[25]: ./media/mobile-services-ios-get-started-push/mobile-quickstart-push3-ios.png
[26]: ./media/mobile-services-ios-get-started-push/mobile-quickstart-push4-ios.png
[28]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-step18.png
[101]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-01.png
[102]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-02.png
[103]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-03.png
[104]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-04.png
[105]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-05.png
[106]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-06.png
[107]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-07.png
[108]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-08.png
[110]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-10.png
[111]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-11.png
[112]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-12.png
[113]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-13.png
[114]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-14.png
[115]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-15.png
[116]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-16.png
[117]: ./media/mobile-services-ios-get-started-push/mobile-services-ios-push-17.png
[Install Xcode]: https://go.microsoft.com/fwLink/p/?LinkID=266532
[iOS Provisioning Portal]: http://go.microsoft.com/fwlink/p/?LinkId=272456
[Mobile Services iOS SDK]: https://go.microsoft.com/fwLink/p/?LinkID=266533
[Apple Push Notification Service]: http://go.microsoft.com/fwlink/p/?LinkId=272584
[Get started with Mobile Services]: mobile-services-ios-get-started.md
[Get started with authentication]: mobile-services-ios-get-started-users.md
[Azure classic portal]: https://manage.windowsazure.com/
[apns object]: http://go.microsoft.com/fwlink/p/?LinkId=272333
[Mobile Services server script reference]: http://go.microsoft.com/fwlink/?LinkId=262293
[Send push notifications to authenticated users]: mobile-services-javascript-backend-ios-push-notifications-app-users.md
[What are Notification Hubs?]: https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-push-notification-overview/
[Send broadcast notifications to subscribers]: https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-ios-xplat-segmented-apns-push-notification/
[Send template-based notifications to subscribers]: https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-ios-xplat-localized-apns-push-notification/
[Mobile Services Objective-C how-to conceptual reference]: mobile-services-windows-dotnet-how-to-use-client-library.md
================================================
FILE: docs/mobile-services-javascript-backend-ios-push-notifications-app-users.md
================================================
# Send Push Notifications to Authenticated Users
> [AZURE.SELECTOR-LIST (Platform | Backend)]
- [(iOS | JavaScript)](mobile-services-javascript-backend-ios-push-notifications-app-users.md)
- [(Windows 8.x Store C# | .NET)](mobile-services-dotnet-backend-windows-store-dotnet-push-notifications-app-users.md)
- [(Windows 8.x Store C# | JavaScript)](mobile-services-javascript-backend-windows-store-dotnet-push-notifications-app-users.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
In this topic, you learn how to send push notifications to an authenticated user on iOS. Before starting this tutorial, complete [Get started with authentication] and [Get started with push notifications] first.
In this tutorial, you require users to authenticate first, register with the notification hub for push notifications, and update server scripts to send those notifications to only authenticated users.
## Update Service to Require Authentication to Register
1. Log on to the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services**, and then click your mobile service.
2. Click the **Push** tab, select **Only Authenticated Users** for **Permissions**, click **Save**, and then click **Edit Script**.
This allows you to customize the push notification registration callback function. If you use Git to edit your source code, this same registration function is found in `.\service\extensions\push.js`.
3. Replace the existing **register** function with the following code and then click **Save**:
exports.register = function (registration, registrationContext, done) {
// Get the ID of the logged-in user.
var userId = registrationContext.user.userId;
// Perform a check here for any disallowed tags.
if (!validateTags(registration))
{
// Return a service error when the client tries
// to set a user ID tag, which is not allowed.
done("You cannot supply a tag that is a user ID");
}
else{
// Add a new tag that is the user ID.
registration.tags.push(userId);
// Complete the callback as normal.
done();
}
};
function validateTags(registration){
for(var i = 0; i < registration.tags.length; i++) {
console.log(registration.tags[i]);
if (registration.tags[i]
.search(/facebook:|twitter:|google:|microsoft:/i) !== -1){
return false;
}
return true;
}
}
This adds a tag to the registration that is the ID of the logged-in user. The supplied tags are validated to prevent a user from registering for another user's ID. When a notification is sent to this user, it is received on this and any other device registered by the user.
4. Click the back arrow, click the **Data** tab, click **TodoItem**, click **Script**, and then select **Insert**.
Replace the `insert` function with the following code, then click **Save**. This insert script uses the user ID tag to send a push notification to all iOS app registrations from the logged-in user:
```
// Get the ID of the logged-in user.
var userId = user.userId;
function insert(item, user, request) {
request.execute();
setTimeout(function() {
push.apns.send(userId, {
alert: "Alert: " + item.text,
payload: {
"Hey, a new item arrived: '" + item.text + "'"
}
});
}, 2500);
}
```
## Update App to Login Before Registration
Next, you need to change the way that push notifications are registered so that a user is authenticated before registration is attempted.
1. In **QSAppDelegate.m**, remove the implementation of **didFinishLaunchingWithOptions** altogether.
2. Open **QSTodoListViewController.m** and add the following code to the end of the **viewDidLoad** method:
```
// Register for remote notifications
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound];
```
## Test App
1. Press **Run** to start the app on a physical iOS device. In the app, add a new item, such as _A new Mobile Services task_, to the todo list.
2. Verify that a notification is received. Additionally -- and optionally -- repeat the above steps on a different physical iOS device, once using the same log-in account and another time using a different log-in account. Verify that notifications are received only by devices authenticating with the same user account.
[Updating the service to require authentication for registration]: #register
[Updating the app to log in before registration]: #update-app
[Testing the app]: #test
[Next Steps]:#next-steps
[Get started with authentication]: mobile-services-ios-get-started-users.md
[Get started with push notifications]: mobile-services-javascript-backend-ios-get-started-push.md
[Mobile Services .NET How-to Conceptual Reference]: mobile-services-ios-how-to-use-client-library.md
================================================
FILE: docs/mobile-services-javascript-backend-phonegap-get-started.md
================================================
# Get started with Mobile Services
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal JavaScript | Javascript)](mobile-services-javascript-backend-windows-store-javascript-get-started.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started.md)
- [(Android | Javascript)](mobile-services-android-get-started.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started.md)
- [(HTML | Javascript)](mobile-services-html-get-started.md)
- [(PhoneGap | Javascript)](mobile-services-javascript-backend-phonegap-get-started.md)
- [(Sencha | Javascript)](partner-sencha-mobile-services-get-started.md)
>[AZURE.TIP] This topic shows you how to get started with Mobile Services as quickly as possible. It is designed for customers new to this Azure feature. If you are already familiar with Mobile Services or are looking for more in-depth information, please select a topic from the left-navigation or see the relevant links in [Next steps](#next-steps).
This tutorial shows you how to add a cloud-based backend service to an app using Azure Mobile Services. In this tutorial, you will create both a new mobile service and a simple _To do list_ app that stores app data in the new mobile service.
A screenshot from the completed app is below:
![][3]
### Additional Requirements
Completing this tutorial requires the following:
+ PhoneGap tools (v3.2+ required for Windows Phone 8 projects).
+ An active Microsoft Azure account.
+ PhoneGap supports developing for multiple platforms. In addition to the PhoneGap tools themselves, you must install the tools for each platform you are targeting:
- Windows Phone: Install [Visual Studio 2012 Express for Windows Phone](https://go.microsoft.com/fwLink/p/?LinkID=268374)
- iOS: Install [Xcode] (v4.4+ required)
- Android: Install the [Android Developer Tools][Android SDK]
(The Mobile Services SDK for Android supports apps for Android 2.2 or a later version. Android 4.2 or higher is required to run the quick start app.)
## Create a new mobile service
Follow these steps to create a new mobile service.
1. Log into the [Azure classic portal](https://manage.windowsazure.com/). At the bottom of the navigation pane, click **+NEW**. Expand **Compute** and **Mobile Service**, then click **Create**.

This displays the **Create a Mobile Service** dialog.
2. In the **Create a Mobile Service** dialog, select **Create a free 20 MB SQL Database**, select **JavaScript** runtime, then type a subdomain name for the new mobile service in the **URL** textbox. Click the right arrow button to go to the next page.

This displays the **Specify database settings** page.
>[AZURE.NOTE]As part of this tutorial, you create a new SQL Database instance and server. You can reuse this new database and administer it as you would any other SQL Database instance. If you already have a database in the same region as the new mobile service, you can instead choose **Use existing Database** and then select that database. The use of a database in a different region is not recommended because of additional bandwidth costs and higher latencies.
3. In **Name**, type the name of the new database, then type **Login name**, which is the administrator login name for the new SQL Database server, type and confirm the password, and click the check button to complete the process.

You have now created a new mobile service that can be used by your mobile apps.
## Create a new PhoneGap app
In this section you will create a new PhoneGap app that is connected to your mobile service.
1. In the [Azure classic portal], click **Mobile Services**, and then click the mobile service that you just created.
2. In the quickstart tab, click **PhoneGap** under **Choose platform** and expand **Create a new PhoneGap app**.
![][0]
This displays the three easy steps to create a PhoneGap app connected to your mobile service.
![][1]
3. If you haven't already done so, download and install PhoneGap and at least one of the platform development tools (Windows Phone, iOS, or Android).
4. Click **Create TodoItem table** to create a table to store app data.
5. Under **Download and run your app**, click **Download**.
This downloads the project for the sample _To do list_ application that is connected to your mobile service, along with the Mobile Services JavaScript SDK. Save the compressed project file to your local computer, and make a note of where you saved it.
## Run your new PhoneGap app
The final stage of this tutorial is to build and run your new app.
1. Browse to the location where you saved the compressed project files and expand the files on your computer.
2. Open and run the project according to the instructions below for each platform.
+ **Windows Phone 8**
1. Windows Phone 8: Open the .sln file in the **platforms\wp8** folder in Visual Studio 2012 Express for Windows Phone.
2. Press the **F5** key to rebuild the project and start the app.
![][2]
+ **iOS**
1. Open the project in the **platforms/ios** folder in Xcode.
2. Press the **Run** button to build the project and start the app in the iPhone emulator, which is the default for this project.
![][3]
+ **Android**
1. In Eclipse, click **File** then **Import**, expand **Android**, click **Existing Android Code into Workspace**, and then click **Next.**
2. Click **Browse**, browse to the location of the expanded project files, click **OK**, make sure that the TodoActivity project is checked, then click **Finish**.
This imports the project files into the current workspace.
3. From the **Run** menu, click **Run** to start the project in the Android emulator.
![][4]
>[AZURE.NOTE]To be able to run the project in the Android emulator, you must define a least one Android Virtual Device (AVD). Use the AVD Manager to create and manage these devices.
3. After launching the app in one of the mobile emulators above, type some text into the textbox and then click **Add**.
This sends a POST request to the new mobile service hosted in Azure. Data from the request is inserted into the **TodoItem** table. Items stored in the table are returned by the mobile service, and the data is displayed in the list.
> [AZURE.IMPORTANT] Changes to this platform project will be overwritten if the main project is rebuilt with the PhoneGap tools. Instead, make changes in the project's root www directory as outlined in the section below.
4. Back in the [Azure classic portal], click the **Data** tab and then click the **TodoItem** table.

This lets you browse the data inserted by the app into the table.

## Make app updates and rebuild projects for each platform
1. Make changes to code files in the ´www´ directory, which in this case is ´todolist/www´.
2. Verify that all of the target platform tools are accessible in the system path.
2. Open a command prompt in the root project directory, and run one of the following platform-specific commands:
+ **Windows Phone**
Run the following command from the Visual Studio Developer command prompt:
phonegap local build wp8
+ **iOS**
Open terminal and run the following command:
phonegap local build ios
+ **Android**
Open a command prompt or terminal window and run the following command.
phonegap local build android
4. Open each project in the appropriate development environment as outlined in the previous section.
>[AZURE.NOTE]You can review the code that accesses your mobile service to query and insert data, which is found in the js/index.js file.
## Next Steps
Now that you have completed the quickstart, learn how to perform additional important tasks in Mobile Services:
* **[Add authentication to your app]**
Learn how to authenticate users of your app with an identity provider.
* **[Add push notifications to your app](https://msdn.microsoft.com/magazine/dn879353.aspx)**
Learn how to register for and send push notifications to your app.
* **[Mobile Services HTML/JavaScript How-to Conceptual Reference](mobile-services-html-how-to-use-client-library.md)**
Learn more about how to use the JavaScript client library to access data, call custom APIs, and perform authentication.
[0]: ./media/mobile-services-javascript-backend-phonegap-get-started/portal-screenshot1.png
[1]: ./media/mobile-services-javascript-backend-phonegap-get-started/portal-screenshot2.png
[2]: ./media/mobile-services-javascript-backend-phonegap-get-started/mobile-portal-quickstart-wp8.png
[3]: ./media/mobile-services-javascript-backend-phonegap-get-started/mobile-portal-quickstart-ios.png
[4]: ./media/mobile-services-javascript-backend-phonegap-get-started/mobile-portal-quickstart-android.png
[Add authentication to your app]: mobile-services-html-get-started-users.md
[Android SDK]: https://go.microsoft.com/fwLink/p/?LinkID=280125
[Azure classic portal]: https://manage.windowsazure.com/
[Xcode]: https://go.microsoft.com/fwLink/p/?LinkID=266532
[Visual Studio 2012 Express for Windows Phone]: https://go.microsoft.com/fwLink/p/?LinkID=268374
================================================
FILE: docs/mobile-services-javascript-backend-service-side-authorization.md
================================================
# Service-side authorization of users in Mobile Services
> [AZURE.SELECTOR]
- [.NET backend](mobile-services-dotnet-backend-service-side-authorization.md)
- [Javascript backend](mobile-services-javascript-backend-service-side-authorization.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
> For the equivalent Mobile Apps version of this topic, see [this sample code](https://github.com/Azure/azure-mobile-apps-node/blob/master/samples/personal-table/tables/TodoItem.js#L38).
This topic shows you how to use server-side scripts to authorize users. In this tutorial, you register scripts with Azure Mobile Services, filter queries based on user IDs, and give users access to only their own data. Filtering a user's query results by the user ID is the most basic form of authorization. Depending on your specific scenario, you might also want to create Users or Roles tables to track more detailed user authorization information, such as which endpoints a given user is permitted to access.
This tutorial is based on the Mobile Services Quick Start and builds on the [Add Authentication to Existing Mobile Services App] tutorial. Please complete [Add Authentication to Existing Mobile Services App] first.
## Register scripts
1. Log on to the [Azure classic portal], click **Mobile Services**, and then click on your mobile service. Click the **Data** tab, then click the **TodoItem** table.
2. Click **Script**, select the **Insert** operation, replace the existing script with the following function, and then click **Save**.
function insert(item, user, request) {
item.userId = user.userId;
request.execute();
}
This script adds the user ID of the authenticated user to the item before insertion.
>[AZURE.NOTE] Make sure that [dynamic schema](https://msdn.microsoft.com/library/azure/jj193175.aspx) is enabled. Otherwise, the *userId* column is not added automatically. This setting is enabled by default for a new mobile service.
3. Similarly, replace the existing **Read** operation with the following function. This script filters returned TodoItem objects so that a user receives only the items that they insert themselves.
function read(query, user, request) {
query.where({ userId: user.userId });
request.execute();
}
## Test the app
1. Notice that when you now run your client-side app, although there are items already in the _TodoItem_ table from previous tutorials, no items are returned. This happens because previous items were inserted without the user ID column and now have null values. Verify newly added items have an associated userId value in the _TodoItem_ table.
2. If you have additional login accounts, verify that users can only see their own data by closing and deleting the app and running it again. When the login credentials dialog is displayed, enter a different login and verify that items entered under the previous login are not displayed.
[Register server scripts]: #register-scripts
[Next Steps]:#next-steps
[Windows Push Notifications & Live Connect]: http://go.microsoft.com/fwlink/p/?LinkID=257677
[Mobile Services server script reference]: http://go.microsoft.com/fwlink/p/?LinkId=262293
[My Apps dashboard]: http://go.microsoft.com/fwlink/p/?LinkId=262039
[Add Authentication to Existing Mobile Services App]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-users-ios
[Azure classic portal]: https://manage.windowsazure.com/
================================================
FILE: docs/mobile-services-javascript-backend-windows-phone-get-started-push.md
================================================
# Add push notifications to your Mobile Services app
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-push.md)
- [(iOS | JavaScript)](mobile-services-javascript-backend-ios-get-started-push.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-push.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-get-started-push.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-javascript-backend-windows-phone-get-started-push.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started-push.md)
- [(Android | Javascript)](mobile-services-javascript-backend-android-get-started-push.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-push.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-push.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-push.md)
- [(Xamarin.Forms | JavaScript)](partner-xamarin-mobile-services-xamarin-forms-get-started-push.md)
## Overview
This topic shows you how to use Azure Mobile Services to send push notifications to a Windows Phone Silverlight app. In this tutorial you enable push notifications using Azure Notification Hubs to the quickstart project. When complete, your mobile service will send a push notification using Notification Hubs each time a record is inserted. The notification hub that you create is free with your mobile service, can be managed independent of the mobile service, and can be used by other applications and services.
This tutorial is based on the TodoList sample app. Before you start this tutorial, you must first complete the topic [Add Mobile Services to an existing app] to connect your project to the mobile service. When a mobile service has not been connected, the Add Push Notification wizard can create this connection for you.
>[AZURE.NOTE] To send push notifications to a Windows Phone 8.1 Store app, follow the [Windows Store app](mobile-services-javascript-backend-windows-universal-dotnet-get-started-push.md) version of this tutorial.
## Update the app to register for notifications
Before your app can receive push notifications, you must register a notification channel.
1. In Visual Studio, open the file App.xaml.cs and add the following `using` statement:
using Microsoft.Phone.Notification;
3. Add the following to App.xaml.cs:
public static HttpNotificationChannel CurrentChannel { get; private set; }
private void AcquirePushChannel()
{
CurrentChannel = HttpNotificationChannel.Find("MyPushChannel");
if (CurrentChannel == null)
{
CurrentChannel = new HttpNotificationChannel("MyPushChannel");
CurrentChannel.Open();
CurrentChannel.BindToShellToast();
}
CurrentChannel.ChannelUriUpdated +=
new EventHandler(async (o, args) =>
{
// Register for notifications using the new channel
await MobileService.GetPush()
.RegisterNativeAsync(CurrentChannel.ChannelUri.ToString());
});
}
This code retrieves the ChannelURI for the app from the Microsoft Push Notification Service (MPNS) used by Windows Phone 8.x "Silverlight", and then registers that ChannelURI for push notifications.
>[AZURE.NOTE]In this this tutorial, the mobile service sends a toast notification to the device. When you send a tile notification, you must instead call the **BindToShellTile** method on the channel.
4. At the top of the **Application_Launching** event handler in App.xaml.cs, add the following call to the new **AcquirePushChannel** method:
AcquirePushChannel();
This makes sure that registration is requested every time that the page is loaded. In your app, you may only want to make this registration periodically to ensure that the registration is current.
5. Press the **F5** key to run the app. A popup dialog with the registration key is displayed.
6. In the Solution Explorer, expand **Properties**, open the WMAppManifest.xml file, click the **Capabilities** tab and make sure that the **ID___CAP___PUSH_NOTIFICATION** capability is checked.

This makes sure that your app can raise toast notifications.
## Update server scripts to send push notifications
Finally, you must update the script registered to the insert operation on the TodoItem table to send notifications.
1. Click **TodoItem**, click **Script** and select **Insert**.
2. Replace the insert function with the following code, and then click **Save**:
function insert(item, user, request) {
// Define a payload for the Windows Phone toast notification.
var payload = '' +
'' +
'New Item' + item.text +
'';
request.execute({
success: function() {
// If the insert succeeds, send a notification.
push.mpns.send(null, payload, 'toast', 22, {
success: function(pushResponse) {
console.log("Sent push:", pushResponse);
request.respond();
},
error: function (pushResponse) {
console.log("Error Sending push:", pushResponse);
request.respond(500, { error: pushResponse });
}
});
}
});
}
This insert script sends a push notification (with the text of the inserted item) to all Windows Phone app registrations after the insert succeeds.
3. Click the **Push** tab, check **Enable unauthenticated push notifications**, then click **Save**.
This enables the mobile service to connect to MPNS in unauthenticated mode to send push notifications.
>[AZURE.NOTE]This tutorial uses MPNS in unauthenticated mode. In this mode, MPNS limits the number of notifications that can be sent to a device channel. To remove this restriction, you must generate and upload a certificate by clicking **Upload** and selecting the certificate. For more information on generating the certificate, see [Setting up an authenticated web service to send push notifications for Windows Phone].
## Test push notifications in your app
1. In Visual Studio, press the F5 key to run the app.
>[AZURE.NOTE] You may encounter a 401 Unauthorized RegistrationAuthorizationException when testing on the Windows Phone emulator. This can occur during the `RegisterNativeAsync()` call because of the way the Windows Phone emulator syncs it's clock with the host PC. It can result in a security token that will be rejected. To resolve this simply manually set the clock in the emulator before testing.
5. In the app, enter the text "hello push" in the textbox, click **Save**, then immediately click the start button or back button to leave the app.

This sends an insert request to the mobile service to store the added item. Notice that the device receives a toast notification that says **hello push**.

>[AZURE.NOTE]You will not receive the notification when you are still in the app. To receive a toast notification while the app is active, you must handle the [ShellToastNotificationReceived](http://msdn.microsoft.com/library/windowsphone/develop/microsoft.phone.notification.httpnotificationchannel.shelltoastnotificationreceived.aspx) event.
## Next steps
This tutorial demonstrated the basics of enabling a Windows Store app to use Mobile Services and Notification Hubs to send push notifications. Next, consider completing one of the following tutorials:
+ [Send broadcast notifications to subscribers](https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-windows-phone-push-xplat-segmented-mpns-notification/)
Learn how users can register and receive push notifications for categories they're interested in.
+ [Send platform-agnostic notifications to subscribers](https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-aspnet-cross-platform-notification/)
Learn how to use templates to send push notifications from your mobile service, without having to craft platform-specific payloads in your back-end.
Learn more about Mobile Services and Notification Hubs in the following topics:
* [Azure Notification Hubs - Diagnosis guidelines](https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-push-notification-fixer/)
Learn how to troubleshoot your push notification issues.
* [Get started with authentication]
Learn how to authenticate users of your app with different account types using mobile services.
* [What are Notification Hubs?]
Learn more about how Notification Hubs works to deliver notifications to your apps across all major client platforms.
* [Mobile Services .NET How-to Conceptual Reference]
Learn more about how to use Mobile Services with .NET.
* [Mobile Services server script reference]
Learn more about how to implement business logic in your mobile service.
[Submit an app page]: http://go.microsoft.com/fwlink/p/?LinkID=266582
[My Applications]: http://go.microsoft.com/fwlink/p/?LinkId=262039
[Live SDK for Windows]: http://go.microsoft.com/fwlink/p/?LinkId=262253
[Add Mobile Services to an existing app]: mobile-services-windows-phone-get-started-data.md
[Get started with authentication]: mobile-services-windows-phone-get-started-users.md
[Setting up an authenticated web service to send push notifications for Windows Phone]: http://msdn.microsoft.com/library/windowsphone/develop/ff941099(v=vs.105).aspx
[Mobile Services server script reference]: http://go.microsoft.com/fwlink/?LinkId=262293
[Mobile Services .NET How-to Conceptual Reference]: mobile-services-windows-dotnet-how-to-use-client-library.md
[What are Notification Hubs?]: https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-push-notification-overview/
================================================
FILE: docs/mobile-services-javascript-backend-windows-store-dotnet-get-started.md
================================================
# Get started with Mobile Services
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal JavaScript | Javascript)](mobile-services-javascript-backend-windows-store-javascript-get-started.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started.md)
- [(Android | Javascript)](mobile-services-android-get-started.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started.md)
- [(HTML | Javascript)](mobile-services-html-get-started.md)
- [(PhoneGap | Javascript)](mobile-services-javascript-backend-phonegap-get-started.md)
- [(Sencha | Javascript)](partner-sencha-mobile-services-get-started.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This tutorial shows you how to add a cloud-based backend service to a universal Windows app using Azure Mobile Services. Universal Windows app solutions include projects for both Windows Store 8.1 and Windows Phone Store 8.1 apps and a common shared project. For more information, see [Build universal Windows apps that target Windows and Windows Phone](http://msdn.microsoft.com/library/windows/apps/xaml/dn609832.aspx).
In this tutorial, you will create both a new mobile service and a simple *To do list* app that stores app data in the new mobile service. The mobile service that you will create uses JavaScript for server-side business logic. To create a mobile service that lets you write your server-side business logic in the supported .NET languages using Visual Studio, see the .NET backend version of this topic.
The following are screen captures from the completed app:

Windows Store app

Windows Phone Store app
Completing this tutorial is a prerequisite for all other Mobile Services tutorials for Windows Store and Windows Phone Store apps.
To complete this tutorial, you need the following:
* An active Azure account. If you don't have an account, you can sign up for an Azure trial and get up to 10 free mobile services that you can keep using even after your trial ends. For details, see [Azure Free Trial](https://azure.microsoft.com/pricing/free-trial/?WT.mc_id=A0E0E5C02&returnurl=http%3A%2F%2Fazure.microsoft.com%2Fen-us%2Fdocumentation%2Farticles%2Fmobile-services-javascript-backend-windows-store-javascript-get-started%2F).
* [Visual Studio 2013 Express for Windows]
## Create a new mobile service
Follow these steps to create a new mobile service.
1. Log into the [Azure classic portal](https://manage.windowsazure.com/). At the bottom of the navigation pane, click **+NEW**. Expand **Compute** and **Mobile Service**, then click **Create**.

This displays the **Create a Mobile Service** dialog.
2. In the **Create a Mobile Service** dialog, select **Create a free 20 MB SQL Database**, select **JavaScript** runtime, then type a subdomain name for the new mobile service in the **URL** textbox. Click the right arrow button to go to the next page.

This displays the **Specify database settings** page.
>[AZURE.NOTE]As part of this tutorial, you create a new SQL Database instance and server. You can reuse this new database and administer it as you would any other SQL Database instance. If you already have a database in the same region as the new mobile service, you can instead choose **Use existing Database** and then select that database. The use of a database in a different region is not recommended because of additional bandwidth costs and higher latencies.
3. In **Name**, type the name of the new database, then type **Login name**, which is the administrator login name for the new SQL Database server, type and confirm the password, and click the check button to complete the process.

You have now created a new mobile service that can be used by your mobile apps.
## Create a new universal Windows app
Once you have created your mobile service, you can follow an easy quickstart in the Azure classic portal to either create a new universal Windows app or modify an existing Windows Store or Windows Phone app project to connect to your mobile service.
In this section you will create a new universal Windows app that is connected to your mobile service.
1. In the [Azure classic portal], click **Mobile Services**, and then click the mobile service that you just created.
2. In the quickstart tab, click **Windows** under **Choose platform** and expand **Create a new Windows Store app**.
This displays the three easy steps to create a Windows Store app connected to your mobile service.

3. If you haven't already done so, download and install [Visual Studio 2013 Express for Windows] on your local computer or virtual machine.
4. Click **Create TodoItem table** to create a table to store app data.
5. Under **Download and run your app**, select a language for your app, then click **Download**.
This downloads the project for the sample *To do list* application that is connected to your mobile service. Save the compressed project file to your local computer, and make a note of where you save it.
## Run your Windows app
The final stage of this tutorial is to build and run your new app.
1. Browse to the location where you saved the compressed project files, expand the files on your computer, and open the solution file in Visual Studio.
2. Press the **F5** key to rebuild the project and start the app.
3. In the app, type meaningful text, such as *Complete the tutorial*, in **Insert a TodoItem**, and then click **Save**.
This sends a POST request to the new mobile service hosted in Azure. Data from the request is inserted into the TodoItem table. Items stored in the table are returned by the mobile service, and the data is displayed in the second column in the app.
4. (Optional) In a universal Windows solution, change the default start up project to the other app and run the app again.
Notice that data saved from the previous step is loaded from the mobile service after the app starts.
4. Back in the [Azure classic portal](https://manage.windowsazure.com/), click the **Data** tab and then click the **TodoItems** table.
This lets you browse the data inserted by the app into the table.

>[AZURE.NOTE]You can review the code that accesses your mobile service to query and insert data, which is found in the MainPage.xaml.cs file.
## Next Steps
Now that you have completed the quickstart, learn how to perform additional important tasks in Mobile Services:
* [Get started with offline data sync]
Learn how to use offline data sync to make your app responsive and robust.
* [Add authentication to your Mobile Services app ][Get started with authentication]
Learn how to authenticate users of your app with an identity provider.
* [Add push notifications to your app][Get started with push notifications]
Learn how to send a very basic push notification to your app.
* [How to use the .NET client library](mobile-services-dotnet-how-to-use-client-library.md)
Learn how to query the mobile service, work with data, and access custom APIs.
[Getting started with Mobile Services]:#getting-started
[Create a new mobile service]:#create-new-service
[Define the mobile service instance]:#define-mobile-service-instance
[Next Steps]:#next-steps
[Get started with offline data sync]: mobile-services-windows-store-dotnet-get-started-offline-data.md
[Get started with authentication]: mobile-services-javascript-backend-windows-universal-dotnet-get-started-users.md
[Get started with push notifications]: mobile-services-javascript-backend-windows-universal-dotnet-get-started-push.md
[Visual Studio 2013 Express for Windows]: http://go.microsoft.com/fwlink/?LinkId=257546
[Mobile Services SDK]: http://go.microsoft.com/fwlink/?LinkId=257545
[Azure classic portal]: https://manage.windowsazure.com/
================================================
FILE: docs/mobile-services-javascript-backend-windows-store-dotnet-push-notifications-app-users.md
================================================
# Send push notifications to authenticated users
> [AZURE.SELECTOR-LIST (Platform | Backend)]
- [(iOS | JavaScript)](mobile-services-javascript-backend-ios-push-notifications-app-users.md)
- [(Windows 8.x Store C# | .NET)](mobile-services-dotnet-backend-windows-store-dotnet-push-notifications-app-users.md)
- [(Windows 8.x Store C# | JavaScript)](mobile-services-javascript-backend-windows-store-dotnet-push-notifications-app-users.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
## Overview
This topic shows you how to send push notifications to an authenticated user on any registered device. Unlike the previous [Add push notifications to your app] tutorial, this tutorial changes your mobile service to require that a user be authenticated before the client can register with the notification hub for push notifications. Registration is also modified to add a tag based on the assigned user ID. Finally, the server script is updated to send the notification only to the authenticated user instead of to all registrations.
This tutorial walks you through the following process:
1. [Updating the service to require authentication for registration]
2. [Updating the app to log in before registration]
3. [Testing the app]
This tutorial supports both Windows Store and Windows Phone Store apps.
## Prerequisites
Before you start this tutorial, you must have already completed these Mobile Services tutorials:
+ [Add authentication to your app] Adds a login requirement to the TodoList sample app.
+ [Add push notifications to your app] Configures the TodoList sample app for push notifications by using Notification Hubs.
After you have completed both tutorials, you can prevent unauthenticated users from registering for push notifications from your mobile service.
## Update the service to require authentication to register
1. Log on to the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services**, and then click your mobile service.
2. Click the **Push** tab, select **Only Authenticated Users** for **Permissions**, click **Save**, and then click **Edit Script**.
This allows you to customize the push notification registration callback function. If you use Git to edit your source code, this same registration function is found in `.\service\extensions\push.js`.
3. Replace the existing **register** function with the following code and then click **Save**:
exports.register = function (registration, registrationContext, done) {
// Get the ID of the logged-in user.
var userId = registrationContext.user.userId;
// Perform a check here for any disallowed tags.
if (!validateTags(registration))
{
// Return a service error when the client tries
// to set a user ID tag, which is not allowed.
done("You cannot supply a tag that is a user ID");
}
else{
// Add a new tag that is the user ID.
registration.tags.push(userId);
// Complete the callback as normal.
done();
}
};
function validateTags(registration){
for(var i = 0; i < registration.tags.length; i++) {
console.log(registration.tags[i]);
if (registration.tags[i]
.search(/facebook:|twitter:|google:|microsoft:/i) !== -1){
return false;
}
return true;
}
}
This adds a tag to the registration that is the ID of the logged-in user. The supplied tags are validated to prevent a user from registering for another user's ID. When a notification is sent to this user, it is received on this and any other device registered by the user.
4. Click the back arrow, click the **Data** tab, click **TodoItem**, click **Script**, and then select **Insert**.
5. Replace the insert function with the following code, then click **Save**:
function insert(item, user, request) {
// Define a payload for the Windows Store toast notification.
var payload = '' +
'' +
item.text + '';
// Get the ID of the logged-in user.
var userId = user.userId;
request.execute({
success: function() {
// If the insert succeeds, send a notification to all devices
// registered to the logged-in user as a tag.
push.wns.send(userId, payload, 'wns/toast', {
success: function(pushResponse) {
console.log("Sent push:", pushResponse);
request.respond();
},
error: function (pushResponse) {
console.log("Error Sending push:", pushResponse);
request.respond(500, { error: pushResponse });
}
});
}
});
}
This insert script uses the user ID tag to send a push notification (with the text of the inserted item) to all Windows Store app registrations created by the logged-in user.
## Update the app to log in before registration
Next, you need to change the way that push notifications are registered to make sure that the user is authenticated before registration is attempted. The client app updates depend on the way in which you implemented push notifications.
### Using the Add Push Notification Wizard in Visual Studio 2013 Update 2 or a later version
In this method, the wizard generated a new push.register.cs file in your project.
1. In Visual Studio in Solution Explorer, open the app.xaml.cs project file and in the **OnLaunched** event handler comment-out or delete the call to the **UploadChannel** method.
2. Open the push.register.cs project file and replace the **UploadChannel** method, with the following code:
public async static void UploadChannel()
{
var channel =
await Windows.Networking.PushNotifications.PushNotificationChannelManager
.CreatePushNotificationChannelForApplicationAsync();
try
{
// Create a native push notification registration.
await App.MobileService.GetPush().RegisterNativeAsync(channel.Uri);
}
catch (Exception exception)
{
HandleRegisterException(exception);
}
}
This makes sure that registration is done using the same client instance that has the authenticated user credentials. Otherwise, registration will fail with an Unauthorized (401) error.
3. Open the shared MainPage.cs project file, and replace the **ButtonLogin_Click** handler with the following:
private async void ButtonLogin_Click(object sender, RoutedEventArgs e)
{
// Login the user and then load data from the mobile service.
await AuthenticateAsync();
todolistPush.UploadChannel();
// Hide the login button and load items from the mobile service.
this.ButtonLogin.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
await RefreshTodoItems();
}
This makes sure that authentication occurs before push registration is attempted.
4. In the previous code, replace the generated push class name (`todolistPush`) with the name of class generated by the wizard, usually in the format mobile_servicePush.
### Manually enabled push notifications
In this method, you added registration code from the tutorial directly to the app.xaml.cs project file.
1. In Visual Studio in Solution Explorer, open the app.xaml.cs project file and in the **OnLaunched** event handler comment-out or delete the call to **InitNotificationsAsync**.
2. Change the accessibility of the **InitNotificationsAsync** method from `private` to `public` and add the `static` modifier.
3. Open the shared MainPage.cs project file, and replace the **ButtonLogin_Click** handler with the following:
private async void ButtonLogin_Click(object sender, RoutedEventArgs e)
{
// Login the user and then load data from the mobile service.
await AuthenticateAsync();
App.InitNotificationsAsync();
// Hide the login button and load items from the mobile service.
this.ButtonLogin.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
await RefreshTodoItems();
}
This makes sure that authentication occurs before push registration is attempted.
## Test the app
1. In Visual Studio, press the F5 key to run the app.
2. Log in using the selected identity provider and verify that authentication succeeds.
3. In the app, type text in **Insert a TodoItem**, and then click **Save**.
Note that after the insert completes, the app receives a push notification from WNS.
4. (Optional) Repeat steps 1-3 on a different client device and using a different account when logging in.
Verify that the notification is received only on this device, since the previous device was not tagged with the current user ID.
[Updating the service to require authentication for registration]: #register
[Updating the app to log in before registration]: #update-app
[Testing the app]: #test
[Next Steps]:#next-steps
[Add authentication to your app]: mobile-services-windows-store-dotnet-get-started-users.md
[Add push notifications to your app]: mobile-services-javascript-backend-windows-store-dotnet-get-started-push.md
================================================
FILE: docs/mobile-services-javascript-backend-windows-store-javascript-get-started.md
================================================
# Get started with Mobile Services
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal JavaScript | Javascript)](mobile-services-javascript-backend-windows-store-javascript-get-started.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started.md)
- [(Android | Javascript)](mobile-services-android-get-started.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started.md)
- [(HTML | Javascript)](mobile-services-html-get-started.md)
- [(PhoneGap | Javascript)](mobile-services-javascript-backend-phonegap-get-started.md)
- [(Sencha | Javascript)](partner-sencha-mobile-services-get-started.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This tutorial shows you how to add a cloud-based backend service to a Windows Store JavaScript app using Azure Mobile Services. In this tutorial, you will create both a new mobile service and a simple *To do list* app that stores app data in the new mobile service. The mobile service that you will create uses JavaScript for server-side business logic.
To complete this tutorial, you need the following:
* An active Azure account. If you don't have an account, you can create a free trial account in just a couple of minutes. For details, see [Azure Free Trial](https://azure.microsoft.com/pricing/free-trial/?WT.mc_id=A0E0E5C02&returnurl=http%3A%2F%2Fazure.microsoft.com%2Fdocumentation%2Farticles%2Fmobile-services-javascript-backend-windows-store-javascript-get-started%2F).
* [Visual Studio 2013 Express for Windows]
## Create a new mobile service
Follow these steps to create a new mobile service.
1. Log into the [Azure classic portal](https://manage.windowsazure.com/). At the bottom of the navigation pane, click **+NEW**. Expand **Compute** and **Mobile Service**, then click **Create**.

This displays the **Create a Mobile Service** dialog.
2. In the **Create a Mobile Service** dialog, select **Create a free 20 MB SQL Database**, select **JavaScript** runtime, then type a subdomain name for the new mobile service in the **URL** textbox. Click the right arrow button to go to the next page.

This displays the **Specify database settings** page.
>[AZURE.NOTE]As part of this tutorial, you create a new SQL Database instance and server. You can reuse this new database and administer it as you would any other SQL Database instance. If you already have a database in the same region as the new mobile service, you can instead choose **Use existing Database** and then select that database. The use of a database in a different region is not recommended because of additional bandwidth costs and higher latencies.
3. In **Name**, type the name of the new database, then type **Login name**, which is the administrator login name for the new SQL Database server, type and confirm the password, and click the check button to complete the process.

You have now created a new mobile service that can be used by your mobile apps.
## Create a new Windows Store app
Once you have created your mobile service, you can follow an easy quickstart in the Azure classic portal to create a new Windows Store 8.1 JavaScript app that connects to your mobile service.
1. In the [Azure classic portal], click **Mobile Services**, and then click the mobile service that you just created.
2. In the quickstart tab, click **Windows** under **Choose platform** and expand **Create a new Windows Store app**.
3. If you haven't already done so, download and install [Visual Studio 2013][Visual Studio 2013 Express for Windows] on your local computer or virtual machine.
4. Click **Create TodoItem table** to create a table to store app data.
5. Under **Download and run your app**, select a language for your app, then click **Download**.
This downloads the project for the sample *To do list* application that is connected to your mobile service. Save the compressed project file to your local computer, and make a note of where you save it.
## Run your Windows app
The final stage of this tutorial is to build and run your new app.
1. Browse to the location where you saved the compressed project files, expand the files on your computer, and open the solution file in Visual Studio.
2. Press the **F5** key to rebuild the project and start the app.
3. In the app, type meaningful text, such as *Complete the tutorial*, in **Insert a TodoItem**, and then click **Save**.
This sends a POST request to the new mobile service hosted in Azure. Data from the request is inserted into the TodoItem table. Items stored in the table are returned by the mobile service, and the data is displayed in the second column in the app.
4. (Optional) Run the app again, and notice that data saved from the previous step is loaded from the mobile service after the app starts.
4. Back in the [Azure classic portal], click the **Data** tab and then click the **TodoItems** table.
This lets you browse the data inserted by the app into the table.
>[AZURE.NOTE] You can review the code that accesses your mobile service to query and insert data, which is found in the default.js file.
## Next Steps
Now that you have completed the quickstart, learn how to work with the [Mobile Services client for HTML/JavaScript](mobile-services-html-how-to-use-client-library.md).
[Getting started with Mobile Services]:#getting-started
[Create a new mobile service]:#create-new-service
[Define the mobile service instance]:#define-mobile-service-instance
[Next Steps]:#next-steps
[Visual Studio 2013 Express for Windows]: http://go.microsoft.com/fwlink/?LinkId=257546
[Mobile Services SDK]: http://go.microsoft.com/fwlink/?LinkId=257545
[Azure classic portal]: https://manage.windowsazure.com/
================================================
FILE: docs/mobile-services-javascript-backend-windows-universal-dotnet-get-started-push.md
================================================
# Add push notifications to your Mobile Services app
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-push.md)
- [(iOS | JavaScript)](mobile-services-javascript-backend-ios-get-started-push.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-push.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-get-started-push.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-javascript-backend-windows-phone-get-started-push.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started-push.md)
- [(Android | Javascript)](mobile-services-javascript-backend-android-get-started-push.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-push.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-push.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-push.md)
- [(Xamarin.Forms | JavaScript)](partner-xamarin-mobile-services-xamarin-forms-get-started-push.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This topic shows you how to use Azure Mobile Services with a JavaScript backend to send push notifications to a universal Windows app. In this tutorial you enable push notifications using Azure Notification Hubs in a universal Windows app project. When complete, your mobile service will send a push notification from the JavaScript backend to all registered Windows Store and Windows Phone Store apps each time a record is inserted in the TodoList table. The notification hub that you create is free with your mobile service, can be managed independent of the mobile service, and can be used by other applications and services.
>[AZURE.NOTE]This topic shows you how to use the tooling in Visual Studio 2013 with Update 3 to add support for push notifications from Mobile Services to a universal Windows app. The same steps can be used to add push notifications from Mobile Services to a Windows Store or Windows Phone Store 8.1 app. To add push notifications to a Windows Phone 8 or Windows Phone Silverlight 8.1 app, see this version of [Get started with push notifications in Mobile Services](mobile-services-javascript-backend-windows-phone-get-started-push.md).
This tutorial walks you through these basic steps to enable push notifications:
1. [Register your app for push notifications](#register)
2. [Update the service to send push notifications](#update-service)
3. [Test push notifications in your app](#test)
To complete this tutorial, you need the following:
* An active [Microsoft Store account](http://go.microsoft.com/fwlink/p/?LinkId=280045).
* [Visual Studio 2013 Express for Windows](http://go.microsoft.com/fwlink/?LinkId=257546) with Update 3, or a later version
## Register your app for push notifications
The following steps registers your app with the Windows Store, configure your mobile service to enable push notifications, and add code to your app to register a device channel with your notification hub. Visual Studio 2013 connects to Azure and to the Windows Store by using the credentials that you provide.
1. In Visual Studio 2013, open Solution Explorer, right-click the Windows Store app project, click **Add** then **Push Notification...**.

This starts the Add Push Notification Wizard.
2. Click **Next**, sign in to your Windows Store account, then supply a name in **Reserve a new name** and click **Reserve**.
This creates a new app registration.
3. Click the new registration in the **App Name** list, then click **Next**.
4. In the **Select a service** page, click the name of your mobile service, then click **Next** and **Finish**.
The notification hub used by your mobile service is updated with the Windows Notification Services (WNS) registration. You can now use Azure Notification Hubs to send notifications from Mobile Services to your app by using WNS.
>[AZURE.NOTE]This tutorial demonstrates sending notifications from a mobile service backend. You can use the same notification hub registration to send notifications from any backend service. For more information, see [Notification Hubs Overview](http://msdn.microsoft.com/library/azure/jj927170.aspx).
5. When you complete the wizard, a new **Push setup is almost complete** page is opened in Visual Studio. This page details an alternate method to configure your mobile service project to send notifications that is different from this tutorial.
The code that is added to your universal Windows app solution by the Add Push Notification wizard is platform-specific. Later in this section, you will remove this redundancy by sharing the Mobile Services client code, which makes the universal app easier to maintain.
[Get started with Mobile Services]: https://azure.microsoft.com/develop/mobile/tutorials/get-started/
[Get started with data]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-data-dotnet/
6. Browse to the `\Services\MobileServices\your_service_name` project folder, open the generated push.register.cs code file, and inspect the **UploadChannel** method that registers the device's channel URL with the notification hub.
7. Open the shared App.xaml.cs code file and notice that a call to the new **UploadChannel** method was added in the **OnLaunched** event handler. This makes sure that registration of the device is attempted whenever the app is launched.
8. Repeat the previous steps to add push notifications to the Windows Phone Store app project, then in the shared App.xaml.cs file, remove the extra call to **Mobile Service Client**, **UploadChannel** and the remaining `#if...#endif` conditional wrapper. Both projects can now share a single call to **UploadChannel**.
Note that you can also simplify the generated code by unifying the `#if...#endif` wrapped [MobileServiceClient] definitions into a single unwrapped definition used by both versions of the app.
Now that push notifications are enabled in the app, you must update the mobile service to send push notifications.
## Update the service to send push notifications
The following steps update the insert script registered to the TodoItem table. You can implement similar code in any server script or anywhere else in your backend services.
Finally, you must update the script registered to the insert operation on the TodoItem table to send notifications.
1. Click **TodoItem**, click **Script** and select **Insert**.
2. Replace the insert function with the following code, and then click **Save**:
function insert(item, user, request) {
// Define a payload for the Windows Store toast notification.
var payload = '' +
'' +
item.text + '';
request.execute({
success: function() {
// If the insert succeeds, send a notification.
push.wns.send(null, payload, 'wns/toast', {
success: function(pushResponse) {
console.log("Sent push:", pushResponse);
request.respond();
},
error: function (pushResponse) {
console.log("Error Sending push:", pushResponse);
request.respond(500, { error: pushResponse });
}
});
}
});
}
This insert script sends a push notification (with the text of the inserted item) to all Windows Store app registrations after the insert succeeds.
## Test push notifications in your app
1. In Visual Studio, right-click the Windows Store project, click **Set as StartUp Project**, then press the F5 key to run the Windows Store app.
After the app starts, the device is registered for push notifications.
2. Stop the Windows Store app and repeat the previous step to run the Windows Phone Store app.
At this point, both devices are registered to receive push notifications.
3. Run the Windows Store app again, and type text in **Insert a TodoItem**, and then click **Save**.

Note that after the insert completes, both the Windows Store and the Windows Phone apps receive a push notification from WNS.

The notification is displayed on Windows Phone even when the app isn't running.

## Next steps
This tutorial demonstrated the basics of enabling a Windows Store app to use Mobile Services and Notification Hubs to send push notifications. Next, consider completing one of the following tutorials:
+ [Send push notifications to authenticated users](mobile-services-javascript-backend-windows-store-dotnet-push-notifications-app-users.md)
Learn how to use tags to send push notifications from your mobile service to only an authenticated user.
+ [Send broadcast notifications to subscribers](https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-windows-notification-dotnet-push-xplat-segmented-wns/)
Learn how users can register and receive push notifications for categories they're interested in.
+ [Send platform-agnostic notifications to subscribers](https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-aspnet-cross-platform-notification/)
Learn how to use templates to send push notifications from your mobile service, without having to craft platform-specific payloads in your back-end.
Learn more about Mobile Services and Notification Hubs in the following topics:
* [Azure Notification Hubs - Diagnosis guidelines](https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-push-notification-fixer/)
Learn how to troubleshoot your push notification issues.
* [Get started with authentication]
Learn how to authenticate users of your app with different account types using mobile services.
* [What are Notification Hubs?]
Learn more about how Notification Hubs works to deliver notifications to your apps across all major client platforms.
* [How to use a .NET client for Azure Mobile Services]
Learn more about how to use Mobile Services from C# Windows apps.
[Submit an app page]: http://go.microsoft.com/fwlink/p/?LinkID=266582
[My Applications]: http://go.microsoft.com/fwlink/p/?LinkId=262039
[Live SDK for Windows]: http://go.microsoft.com/fwlink/p/?LinkId=262253
[Get started with Mobile Services]: mobile-services-dotnet-backend-windows-store-dotnet-get-started.md
[Get started with authentication]: mobile-services-javascript-backend-windows-universal-dotnet-get-started-users.md
[Send push notifications to authenticated users]: mobile-services-javascript-backend-windows-store-dotnet-push-notifications-app-users.md
[What are Notification Hubs?]: https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-push-notification-overview/
[How to use a .NET client for Azure Mobile Services]: mobile-services-windows-dotnet-how-to-use-client-library.md
[MobileServiceClient]: http://go.microsoft.com/fwlink/p/?LinkId=302030
================================================
FILE: docs/mobile-services-javascript-backend-windows-universal-dotnet-get-started-users.md
================================================
# Add authentication to your universal Windows 8.1 app
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-users.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started-users.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-users.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-get-started-users.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-windows-phone-get-started-users.md)
- [(Android | Javascript)](mobile-services-android-get-started-users.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started-users.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-users.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-users.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-users.md)
- [(HTML | Javascript)](mobile-services-html-get-started-users.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This topic shows you how to authenticate users in Azure Mobile Services from your universal Windows 8.1 app. In this tutorial, you add authentication to the quickstart project using an identity provider that is supported by Mobile Services. After being successfully authenticated and authorized by Mobile Services, the user ID value is displayed.
This tutorial is based on the Mobile Services quickstart. You must also first complete the tutorial [Get started with Mobile Services].
>[AZURE.NOTE]This tutorial shows you how to authenticate users in Windows Store and Windows Phone Store 8.1 apps. For a Windows Phone 8.0 or Windows Phone Silverlight 8.1 app, see this version of [Get started with authentication in Mobile Services](mobile-services-windows-phone-get-started-users.md).
## Register your app for authentication and configure Mobile Services
1. In the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Dashboard**, and make a note of the **Mobile Service URL** value.
2. Register your app with one or more of the following authentication providers:
* [Google](./
mobile-services-how-to-register-google-authentication.md)
* [Facebook](./
mobile-services-how-to-register-facebook-authentication.md)
* [Twitter](./
mobile-services-how-to-register-twitter-authentication.md)
* [Microsoft](./
mobile-services-how-to-register-microsoft-authentication.md)
* [Azure Active Directory](./
mobile-services-how-to-register-active-directory-authentication.md).
Make a note of the client identity and client secret values generated by the provider. Do not distribute or share the client secret.
3. Back in the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Identity** > your identity provider settings, then enter the client ID and secret value from your provider.
You've now configured both your app and your mobile service to work with your auth provider. You may optionally repeat all these steps for each additional identity provider you'd like to support.
> [AZURE.IMPORTANT] Verify that you've set the correct redirect URI on your identity provider's developer site. As described in the linked instructions for each provider above, the redirect URI may be different for a .NET backend service vs. for a JavaScript backend service. An incorrectly configured redirect URI may result in the login screen not being displayed properly and the app malfunctioning in unexpected ways.
## Restrict permissions to authenticated users
1. In the Server Explorer in Visual Studio, expand the **Azure** node, **Mobile Services**, and your mobile service.
2. Right-click the **TodoItem** table, click **Edit Permissions**, set all permissions to **Only authenticated users**, and then click **Apply**. This ensures that all operations against the _TodoItem_ table require an authenticated user.
3. Right-click the client app project, click **Debug**, then **Start new instance**; verify that an unhandled exception with a status code of 401 (Unauthorized) is raised after the app starts.
This happens because the app attempts to access Mobile Services as an unauthenticated user, but the *TodoItem* table now requires authentication.
Next, you will update the app to authenticate users before requesting resources from the mobile service.
>[AZURE.NOTE] When you use Visual Studio tools to connect your app to a Mobile Service, the tool generate two sets of **MobileServiceClient** definitions, one for each client platform. This is a good time to simplify the generated code by unifying the `#if...#endif` wrapped **MobileServiceClient** definitions into a single unwrapped definition used by both versions of the app. You won't need to do this if you downloaded the quickstart app from the [Azure classic portal].
## Add authentication to the app
1. Open the shared project file MainPage.cs and add the following code snippet to the MainPage class:
// Define a member variable for storing the signed-in user.
private MobileServiceUser user;
// Define a method that performs the authentication process
// using a Facebook sign-in.
private async System.Threading.Tasks.Task AuthenticateAsync()
{
string message;
bool success = false;
try
{
// Change 'MobileService' to the name of your MobileServiceClient instance.
// Sign-in using Facebook authentication.
user = await App.MobileService
.LoginAsync(MobileServiceAuthenticationProvider.Facebook);
message =
string.Format("You are now signed in - {0}", user.UserId);
success = true;
}
catch (InvalidOperationException)
{
message = "You must log in. Login Required";
}
var dialog = new MessageDialog(message);
dialog.Commands.Add(new UICommand("OK"));
await dialog.ShowAsync();
return success;
}
This code authenticates the user with a Facebook login. If you are using an identity provider other than Facebook, change the value of **MobileServiceAuthenticationProvider** above to the value for your provider.
3. Comment-out or delete the call to the **RefreshTodoItems** method in the existing **OnNavigatedTo** method override.
This prevents the data from being loaded before the user is authenticated. Next, you will add a **Sign in** button to the app that triggers authentication.
4. Add the following code snippet to the MainPage class:
private async void ButtonLogin_Click(object sender, RoutedEventArgs e)
{
// Login the user and then load data from the mobile app.
if (await AuthenticateAsync())
{
// Hide the login button and load items from the mobile app.
ButtonLogin.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
//await InitLocalStoreAsync(); //offline sync support.
await RefreshTodoItems();
}
}
5. In the Windows Store app project, open the MainPage.xaml project file and add the following **Button** element just before the element that defines the **Save** button:
6. In the Windows Phone Store app project, add the following **Button** element in the **ContentPanel**, after the **TextBox** element:
8. Open the shared App.xaml.cs project file and add the following code:
protected override void OnActivated(IActivatedEventArgs args)
{
// Windows Phone 8.1 requires you to handle the respose from the WebAuthenticationBroker.
#if WINDOWS_PHONE_APP
if (args.Kind == ActivationKind.WebAuthenticationBrokerContinuation)
{
// Completes the sign-in process started by LoginAsync.
// Change 'MobileService' to the name of your MobileServiceClient instance.
App.MobileService.LoginComplete(args as WebAuthenticationBrokerContinuationEventArgs);
}
#endif
base.OnActivated(args);
}
If the **OnActivated** method already exists, just add the `#if...#endif` code block.
9. Press the F5 key to run the Windows Store app, click the **Sign in** button, and sign into the app with your chosen identity provider.
When you are successfully logged-in, the app should run without errors, and you should be able to query your backend and make updates to data.
10. Right-click the Windows Phone Store app project, click **Set as StartUp Project**, then repeat the previous step to verify that the Windows Phone Store app also runs correctly.
Now, any user authenticated by your trusted identity providers can access the *TodoItem* table. To better secure user-specific data, you must also implement authorization. To do this you get the user ID of a given user, which can then be used to determine what level of access that user should have for a given resource.
## Store the authorization token on the client
The previous example showed a standard sign-in, which requires the client to contact both the identity provider and the mobile service every time that the app starts. Not only is this method inefficient, you can run into usage-related issues should many customers try to start your app at the same time. A better approach is to cache the authorization token returned by Mobile Services and try to use this first before using a provider-based sign-in.
>[AZURE.NOTE]You can cache the token issued by Mobile Services regardless of whether you are using client-managed or service-managed authentication. This tutorial uses service-managed authentication.
1. In the MainPage.xaml.cs project file, add the following **using** statements:
using System.Linq;
using Windows.Security.Credentials;
2. Replace the **AuthenticateAsync** method with the following code:
private async System.Threading.Tasks.Task AuthenticateAsync()
{
string message;
bool success = false;
// This sample uses the Facebook provider.
var provider = MobileServiceAuthenticationProvider.Facebook;
// Use the PasswordVault to securely store and access credentials.
PasswordVault vault = new PasswordVault();
PasswordCredential credential = null;
try
{
// Try to get an existing credential from the vault.
credential = vault.FindAllByResource(provider.ToString()).FirstOrDefault();
}
catch (Exception)
{
// When there is no matching resource an error occurs, which we ignore.
}
if (credential != null)
{
// Create a user from the stored credentials.
user = new MobileServiceUser(credential.UserName);
credential.RetrievePassword();
user.MobileServiceAuthenticationToken = credential.Password;
// Set the user from the stored credentials.
App.MobileService.CurrentUser = user;
// Consider adding a check to determine if the token is
// expired, as shown in this post: http://aka.ms/jww5vp.
success = true;
message = string.Format("Cached credentials for user - {0}", user.UserId);
}
else
{
try
{
// Login with the identity provider.
user = await App.MobileService
.LoginAsync(provider);
// Create and store the user credentials.
credential = new PasswordCredential(provider.ToString(),
user.UserId, user.MobileServiceAuthenticationToken);
vault.Add(credential);
success = true;
message = string.Format("You are now logged in - {0}", user.UserId);
}
catch (MobileServiceInvalidOperationException)
{
message = "You must log in. Login Required";
}
}
var dialog = new MessageDialog(message);
dialog.Commands.Add(new UICommand("OK"));
await dialog.ShowAsync();
return success;
}
In this version of **AuthenticateAsync**, the app tries to use credentials stored in the **PasswordVault** to access the service. A regular sign-in is also performed when there is no stored credential.
>[AZURE.NOTE]A cached token may be expired, and token expiration can also occur after authentication when the app is in use. To learn how to determine if a token is expired, see [Check for expired authentication tokens](http://aka.ms/jww5vp). For a solution to handling authorization errors related to expiring tokens, see the post [Caching and handling expired tokens in Azure Mobile Services managed SDK](http://blogs.msdn.com/b/carlosfigueira/archive/2014/03/13/caching-and-handling-expired-tokens-in-azure-mobile-services-managed-sdk.aspx).
3. Restart the app twice.
Notice that on the first start-up, sign-in with the provider is again required. However, on the second restart the cached credentials are used and sign-in is bypassed.
## Next steps
In the next tutorial, [Service-side authorization of Mobile Services users](mobile-services-javascript-backend-service-side-authorization.md), you will take the user ID value provided by Mobile Services based on an authenticated user and use it to filter the data returned by Mobile Services.
## See also
+ [Enhanced users feature](http://go.microsoft.com/fwlink/p/?LinkId=506605)
You can get additional user data maintained by the identity provider in your mobile service by by calling the **user.getIdentities()** function in server scripts.
+ [Mobile Services .NET How-to Conceptual Reference] Learn more about how to use Mobile Services with a .NET client.
[Register your app for authentication and configure Mobile Services]: #register
[Restrict table permissions to authenticated users]: #permissions
[Add authentication to the app]: #add-authentication
[Store authentication tokens on the client]: #tokens
[Next Steps]:#next-steps
[Submit an app page]: http://go.microsoft.com/fwlink/p/?LinkID=266582
[My Applications]: http://go.microsoft.com/fwlink/p/?LinkId=262039
[Live SDK for Windows]: http://go.microsoft.com/fwlink/p/?LinkId=262253
[Get started with Mobile Services]: mobile-services-javascript-backend-windows-store-dotnet-get-started.md
[Get started with authentication]: mobile-services-javascript-backend-windows-store-dotnet-get-started-users.md
[Get started with push notifications]: mobile-services-javascript-backend-windows-store-dotnet-get-started-push.md
[Authorize users with scripts]: mobile-services-windows-store-dotnet-authorize-users-in-scripts.md
[Azure classic portal]: https://manage.windowsazure.com/
[Mobile Services .NET How-to Conceptual Reference]: mobile-services-windows-dotnet-how-to-use-client-library.md
[Register your Windows Store app package for Microsoft authentication]: mobile-services-how-to-register-store-app-package-microsoft-authentication.md
================================================
FILE: docs/mobile-services-javascript-backend-windows-universal-dotnet-upload-data-blob-storage.md
================================================
# Upload images to Azure Blob storage by using Mobile Services
> [AZURE.SELECTOR-LIST (Platform | Backend)]
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-upload-data-blob-storage.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-upload-data-blob-storage.md)
- [(Android | Javascript)](mobile-services-android-upload-data-blob-storage.md)
## Overview
This topic shows you how to use Azure Mobile Services to enable your app to upload and store user-generated images in Azure Storage. Mobile Services uses a SQL Database to store data. However, binary large object (BLOB) data is more efficiently stored in Azure Blob storage service.
You cannot securely distribute with the client app the credentials required to securely upload data to the Blob Storage service. Instead, you must store these credentials in your mobile service and use them to generate a Shared Access Signature (SAS) that is used to upload a new image. The SAS, a credential with a short expiration—in this case 5 minutes, is returned securely by Mobile Services to the client app. The app then uses this temporary credential to upload the image. In this example, downloads from the Blob service are public.
In this tutorial you add functionality to the Mobile Services quickstart app to take pictures and upload the images to Azure by using an SAS generated by Mobile Services.
## Prerequisites
This tutorial requires the following:
+ Microsoft Visual Studio 2013 Update 3, or a later version
+ [Azure Storage account](https://azure.microsoft.com/en-us/documentation/articles/storage-create-storage-account/)
+ A camera or other image capture device attached to your computer.
This tutorial is based on the Mobile Services quickstart. Before you start this tutorial, you must first complete [Get started with Mobile Services].
## Update the registered insert script in the Azure classic portal
A new insert script is registered that generates an SAS when a new Todo item is inserted.
0. If you haven't yet created your storage account, see [How To Create a Storage Account](https://azure.microsoft.com/en-us/documentation/articles/storage-create-storage-account/).
1. In the [Azure classic portal](https://manage.windowsazure.com/), click **Storage**, click the storage account, then click **Manage Keys**.
2. Make a note of the **Storage Account Name** and **Access Key**.

3. In your mobile service, click the **Configure** tab, scroll down to **App settings** and enter a **Name** and **Value** pair for each of the following that you obtained from the storage account, then click **Save**.
+ `STORAGE_ACCOUNT_NAME`
+ `STORAGE_ACCOUNT_ACCESS_KEY`

The storage account access key is stored encrypted in app settings. You can access this key from any server script at runtime. For more information, see [App settings].
4. In the Configure tab, make sure that [Dynamic schema](http://msdn.microsoft.com/library/windowsazure/b6bb7d2d-35ae-47eb-a03f-6ee393e170f7) is enabled. You need dynamic schema enabled to be able to add new columns to the TodoItem table. Dynamic schema should not be enabled in any production service.
4. Click the **Data** tab and then click the **TodoItem** table.
5. In **todoitem**, click the **Script** tab and select **Insert**, replace the insert function with the following code, then click **Save**:
var azure = require('azure');
var qs = require('querystring');
var appSettings = require('mobileservice-config').appSettings;
function insert(item, user, request) {
// Get storage account settings from app settings.
var accountName = appSettings.STORAGE_ACCOUNT_NAME;
var accountKey = appSettings.STORAGE_ACCOUNT_ACCESS_KEY;
var host = accountName + '.blob.core.windows.net';
if ((typeof item.containerName !== "undefined") && (
item.containerName !== null)) {
// Set the BLOB store container name on the item, which must be lowercase.
item.containerName = item.containerName.toLowerCase();
// If it does not already exist, create the container
// with public read access for blobs.
var blobService = azure.createBlobService(accountName, accountKey, host);
blobService.createContainerIfNotExists(item.containerName, {
publicAccessLevel: 'blob'
}, function(error) {
if (!error) {
// Provide write access to the container for the next 5 mins.
var sharedAccessPolicy = {
AccessPolicy: {
Permissions: azure.Constants.BlobConstants.SharedAccessPermissions.WRITE,
Expiry: new Date(new Date().getTime() + 5 * 60 * 1000)
}
};
// Generate the upload URL with SAS for the new image.
var sasQueryUrl =
blobService.generateSharedAccessSignature(item.containerName,
item.resourceName, sharedAccessPolicy);
// Set the query string.
item.sasQueryString = qs.stringify(sasQueryUrl.queryString);
// Set the full path on the new new item,
// which is used for data binding on the client.
item.imageUri = sasQueryUrl.baseUrl + sasQueryUrl.path;
} else {
console.error(error);
}
request.execute();
});
} else {
request.execute();
}
}
This replaces the function that is invoked when an insert occurs in the TodoItem table with a new script. This new script generates a new SAS for the insert, which is valid for 5 minutes, and assigns the value of the generated SAS to the `sasQueryString` property of the returned item. The `imageUri` property is also set to the resource path of the new BLOB to enable image display during binding in the client UI.
>[AZURE.NOTE] This code creates an SAS for an individual BLOB. If you need to upload multiple blobs to a container using the same SAS, you can instead call the [generateSharedAccessSignature method](http://go.microsoft.com/fwlink/?LinkId=390455) with an empty blob resource name, like this:
>
> blobService.generateSharedAccessSignature(containerName, '', sharedAccessPolicy);
Next, you will update the quickstart app to add image upload functionality by using the SAS generated on insert.
[App settings]: http://msdn.microsoft.com/library/windowsazure/b6bb7d2d-35ae-47eb-a03f-6ee393e170f7
## Install the Storage client for Windows Store apps
To be able to use an SAS to upload images to Blob storage, you must first add the NuGet package that installs Storage client library for Windows Store apps.
1. In **Solution Explorer** in Visual Studio, right-click the project name, and then select **Manage NuGet Packages**.
2. In the left pane, select the **Online** category, search for `WindowsAzure.Storage`, click **Install** on the **Azure Storage** package, then accept the license agreements.

This adds the client library for Azure storage services to the project.
Next, you will update the quickstart app to capture and upload images.
## Update the quickstart client app to capture and upload images
1. In Visual Studio, open the Package.appxmanifest file for the Windows app project and in the **Capabilities** tab enable the **Webcam** and **Microphone** capabilities.

This makes sure that your app can use a camera attached to the computer. Users will be requested to allow camera access the first time that the app is run.
2. Repeat the step above for the Windows Phone app project.
3. In the Windows app project, open the MainPage.xaml file and replace the **StackPanel** element directly after the first **QuickStartTask** element with the following code:
2. Replace the **StackPanel** element in the **DataTemplate** with the following code:
This adds an image to the **ItemTemplate** and sets its binding source as the URI of the uploaded image in the Blob Storage service.
3. In the Windows Phone app project, open the MainPage.xaml file and replace the **ButtonSave** element with the following code:
2. Replace the **StackPanel** element in the **DataTemplate** with the following code:
4. In the shared DataModel folder, open the TodoItem.cs project file and add add the following properties to the TodoItem class:
[JsonProperty(PropertyName = "containerName")]
public string ContainerName { get; set; }
[JsonProperty(PropertyName = "resourceName")]
public string ResourceName { get; set; }
[JsonProperty(PropertyName = "sasQueryString")]
public string SasQueryString { get; set; }
[JsonProperty(PropertyName = "imageUri")]
public string ImageUri { get; set; }
3. Open the shared MainPage.cs project file and add the following **using** statements:
using Windows.Media.Capture;
using Windows.Media.MediaProperties;
using Windows.Storage;
using Windows.UI.Xaml.Input;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Blob;
using Windows.UI.Xaml.Media.Imaging;
5. Add the following code to the MainPage class:
// Use a StorageFile to hold the captured image for upload.
StorageFile media = null;
MediaCapture cameraCapture;
bool IsCaptureInProgress;
private async Task CaptureImage()
{
// Capture a new photo or video from the device.
cameraCapture = new MediaCapture();
cameraCapture.Failed += cameraCapture_Failed;
// Initialize the camera for capture.
await cameraCapture.InitializeAsync();
#if WINDOWS_PHONE_APP
cameraCapture.SetPreviewRotation(VideoRotation.Clockwise90Degrees);
cameraCapture.SetRecordRotation(VideoRotation.Clockwise90Degrees);
#endif
captureGrid.Visibility = Windows.UI.Xaml.Visibility.Visible;
previewElement.Visibility = Windows.UI.Xaml.Visibility.Visible;
previewElement.Source = cameraCapture;
await cameraCapture.StartPreviewAsync();
}
private async void previewElement_Tapped(object sender, TappedRoutedEventArgs e)
{
// Block multiple taps.
if (!IsCaptureInProgress)
{
IsCaptureInProgress = true;
// Create the temporary storage file.
media = await ApplicationData.Current.LocalFolder
.CreateFileAsync("capture_file.jpg", CreationCollisionOption.ReplaceExisting);
// Take the picture and store it locally as a JPEG.
await cameraCapture.CapturePhotoToStorageFileAsync(
ImageEncodingProperties.CreateJpeg(), media);
captureButtons.Visibility = Visibility.Visible;
// Use the stored image as the preview source.
BitmapImage tempBitmap = new BitmapImage(new Uri(media.Path));
imagePreview.Source = tempBitmap;
imagePreview.Visibility = Visibility.Visible;
previewElement.Visibility = Visibility.Collapsed;
IsCaptureInProgress = false;
}
}
private async void cameraCapture_Failed(MediaCapture sender, MediaCaptureFailedEventArgs errorEventArgs)
{
// It's safest to return this back onto the UI thread to show the message dialog.
MessageDialog dialog = new MessageDialog(errorEventArgs.Message);
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
async () => { await dialog.ShowAsync(); });
}
private async void ButtonCapture_Click(object sender, RoutedEventArgs e)
{
// Prevent multiple initializations.
ButtonCapture.IsEnabled = false;
await CaptureImage();
}
private async void ButtonRetake_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
// Reset the capture and then start again.
await ResetCaptureAsync();
await CaptureImage();
}
private async void ButtonCancel_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
await ResetCaptureAsync();
}
private async Task ResetCaptureAsync()
{
captureGrid.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
imagePreview.Visibility = Visibility.Collapsed;
captureButtons.Visibility = Visibility.Collapsed;
previewElement.Source = null;
ButtonCapture.IsEnabled = true;
// Make sure we stop the preview and release resources.
await cameraCapture.StopPreviewAsync();
cameraCapture.Dispose();
media = null;
}
This code displays the UI used to capture an image, and saves the image to a storage file.
6. Replace the existing `InsertTodoItem` method with the following code:
private async Task InsertTodoItem(TodoItem todoItem)
{
string errorString = string.Empty;
if (media != null)
{
// Set blob properties of TodoItem.
todoItem.ContainerName = "todoitemimages";
// Use a unigue GUID to avoid collisions.
todoItem.ResourceName = Guid.NewGuid().ToString();
}
// Send the item to be inserted. When blob properties are set this
// generates an SAS in the response.
await todoTable.InsertAsync(todoItem);
// If we have a returned SAS, then upload the blob.
if (!string.IsNullOrEmpty(todoItem.SasQueryString))
{
// Get the URI generated that contains the SAS
// and extract the storage credentials.
StorageCredentials cred = new StorageCredentials(todoItem.SasQueryString);
var imageUri = new Uri(todoItem.ImageUri);
// Instantiate a Blob store container based on the info in the returned item.
CloudBlobContainer container = new CloudBlobContainer(
new Uri(string.Format("https://{0}/{1}",
imageUri.Host, todoItem.ContainerName)), cred);
// Get the new image as a stream.
using (var inputStream = await media.OpenReadAsync())
{
// Upload the new image as a BLOB from the stream.
CloudBlockBlob blobFromSASCredential =
container.GetBlockBlobReference(todoItem.ResourceName);
await blobFromSASCredential.UploadFromStreamAsync(inputStream);
}
// When you request an SAS at the container-level instead of the blob-level,
// you are able to upload multiple streams using the same container credentials.
await ResetCaptureAsync();
}
// Add the new item to the collection.
items.Add(todoItem);
}
This code sends a request to the mobile service to insert a new TodoItem. The response contains the SAS, which is then used to upload the image from local storage to Azure Blob storage. The URL of the uploaded image is used in data binding.
The final step is to test both versions of the app and validate that uploads succeed from both devices.
## Test uploading the images in your app
1. In Visual Studio, make sure that the Windows project is set as the default project, then press the F5 key to run the app.
2. Enter text in the textbox under **Insert a TodoItem**, then click **Photo**.
3. Click or tap the preview to take a picture, then click **Upload** to insert the new item and upload the image.

4. The new item, along with the uploaded image, is displayed in the list view.

>[AZURE.NOTE]The image is downloaded automatically from Blob storage when the *imageUri* property of the new item is bound to the **Image** control.
5. Stop the app and restart the Windows Phone project version of the app.
The previously uploaded image is displayed.
6. As before, enter some text in the textbox, then click **Photo**.

3. Tap the preview to take a picture, then click **Upload** to insert the new item and upload the image.

You have completed the upload images tutorial.
## Next steps
Now that you have been able to securely upload images by integrating your mobile service with the Blob service, check out some of the other backend service and integration topics:
+ [Schedule backend jobs in Mobile Services]
Learn how to use the Mobile Services job scheduler functionality to define server script code that is executed on a schedule that you define.
+ [Mobile Services server script reference]
Reference topics for using server scripts to perform server-side tasks and integration with other Azure components and external resources.
+ [Mobile Services .NET How-to Conceptual Reference]
Learn more about how to use Mobile Services with .NET
[Install the Storage Client library]: #install-storage-client
[Update the client app to capture images]: #add-select-images
[Update the insert script to generate an SAS]: #update-scripts
[Upload images to test the app]: #test
[Next Steps]:#next-steps
[2]: ./media/mobile-services-windows-store-dotnet-upload-data-blob-storage/mobile-add-storage-nuget-package-dotnet.png
[Send email from Mobile Services with SendGrid]: store-sendgrid-mobile-services-send-email-scripts.md
[Schedule backend jobs in Mobile Services]: mobile-services-schedule-recurring-tasks.md
[Send push notifications to Windows Store apps using Service Bus from a .NET back-end]: http://go.microsoft.com/fwlink/?LinkId=277073&clcid=0x409
[Mobile Services server script reference]: mobile-services-how-to-use-server-scripts.md
[Get started with Mobile Services]: mobile-services-javascript-backend-windows-store-dotnet-get-started.md
[How To Create a Storage Account]: https://azure.microsoft.com/en-us/documentation/articles/storage-create-storage-account/
[Azure Storage Client library for Store apps]: http://go.microsoft.com/fwlink/p/?LinkId=276866
[Mobile Services .NET How-to Conceptual Reference]: mobile-services-windows-dotnet-how-to-use-client-library.md
[App settings]: http://msdn.microsoft.com/library/windowsazure/b6bb7d2d-35ae-47eb-a03f-6ee393e170f7
================================================
FILE: docs/mobile-services-manage-command-line-interface.md
================================================
# Automate mobile services with command-line tools
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
## Overview
This topic shows you how to use the Azure command-line tools to automate the creation and management of Azure Mobile Services. This topic shows you how to install and get started using the command-line tools and use them to perform key Mobile Services.
When combined into a single script or batch file, these individual commands automate the creation, verification, and deletion process of a mobile service.
This topic covers a selection of common administration tasks supported by the Azure command-line tools. For more information, see [Azure command-line tools documentation][reference-docs].
## Install the Azure Command-Line Tools
The following list contains information for installing the command-line tools, depending on your operating system:
* **Windows**: Download the [Azure Command-Line Tools Installer][windows-installer]. Open the downloaded .msi file and complete the installation steps as you are prompted.
* **Mac**: Download the [Azure SDK Installer][mac-installer]. Open the downloaded .pkg file and complete the installation steps as you are prompted.
* **Linux**: Install the latest version of [Node.js][nodejs-org] (see [Install Node.js via Package Manager][install-node-linux]), then run the following command:
npm install azure-cli -g
To test the installation, type `azure` at the command prompt. When the installation is successful, you will see a list of all the available `azure` commands.
## How to download and import publish settings
To get started, you must first download and import your publish settings. Then you can use the tools to create and manage Azure Services. To download your publish settings, use the `account download` command:
azure account download
This opens your default browser and prompts you to sign in to the Azure classic portal. After signing in, your `.publishsettings` file is downloaded. Note the location of this saved file.
Next, import the `.publishsettings` file by running the following command, replacing `` with the path to your `.publishsettings` file:
azure account import
You can remove all of the information stored by the import command by using the account clear command:
azure account clear
To see a list of options for `account` commands, use the `-help` option:
azure account -help
After importing your publish settings, you should delete the `.publishsettings` file for security reasons. For more information, see [How to install the Azure Command-Line Tools for Mac and Linux]. You are now ready to begin creating and managing Azure Mobile Services from the command line or in batch files.
## How to create a mobile service
You can use the command-line tools to create a new mobile service instance. While creating the mobile service, you also create a SQL Database instance in a new server.
The following command creates a new mobile service instance in your subscription, where `` is the name of the new mobile service, `` is the login name of the new server, and `` is the password for the new login:
azure mobile create
The `mobile create` command fails when the specified mobile service exists. In your automation scripts, you should attempt to delete a mobile service before attempting to recreate it.
## How to list existing mobile services in a subscription
> [AZURE.NOTE] Commands in the CLI related to "list" and "script" only work with the JavaScript backend.
The following command returns a list of all the mobile services in an Azure subscription:
azure mobile list
This command also shows the current state and URL of each mobile service.
## How to delete an existing mobile service
You can use the command-line tools to delete an existing mobile service, along with the related SQL Database and server. The following command deletes the mobile service, where `` is the name of the mobile service to delete:
azure mobile delete -a -q
By including `-a` and `-q` parameters, this command also deletes the SQL Database and server used by the mobile service without displaying a prompt.
> [AZURE.NOTE] If you do not specify the -q parameter along with -a or -d, execution is paused and you are prompted to select delete options for your SQL Database. Only use the -a parameter when no other service uses the database or server; otherwise use the -d parameter to only delete data that belongs to the mobile service being deleted.
## How to create a table in the mobile service
The following command creates a table in the specified mobile service, where `` is the name of the mobile service and `` is the name of the table to create:
azure mobile table create
This creates a new table with the default permissions, `application`, for the table operations: `insert`, `read`, `update`, and `delete`.
The following command creates a new table with public `read` permission but with `delete` permission granted only to administrators:
azure mobile table create -p read=public,delete=admin
The following table shows the script permission value compared to the permission value in the [Azure classic portal].
|Script value|Portal value|
|========|========|
|`public`|Everyone|
|`application`(default)|Anybody with the application key|
|`user`|Only authenticated users|
|`admin`|Only scripts and admins|
The `mobile table create` command fails when the specified table already exists. In your automation scripts, you should attempt to delete a table before attempting to recreate it.
## How to list existing tables in a mobile service
The following command returns a list of all of the tables in a mobile service, where `` is the name of the mobile service:
azure mobile table list
This command also shows the number of indexes on each table and the number of data rows currently in the table.
## How to delete an existing table from the mobile service
The following command deletes a table from the mobile service, where `` is the name of the mobile service and `` is the name of the table to delete:
azure mobile table delete -q
In automation scripts, use the `-q` parameter to delete the table without displaying a confirmation prompt that blocks execution.
## How to register a script to a table operation
The following command uploads and registers a function to an operation on a table, where `` is the name of the mobile service, `` is the name of the table, and `` is the table operation, which can be `read`, `insert`, `update`, or `delete`:
azure mobile script upload table/..js
Note that this operation uploads a JavaScript (.js) file from the local computer. The name of the file must be composed from the table and operation names, and it must be located in the `table` subfolder relative to the location where the command is executed. For example, the following operation uploads and registers a new `insert` script that belongs to the `TodoItems` table:
azure mobile script upload todolist table/todoitems.insert.js
The function declaration in the script file must also match the registered table operation. This means that for an `insert` script, the uploaded script contains a function with the following signature:
function insert(item, user, request) {
...
}
For more information about registering scripts, see [Mobile Services server script reference].
[Download and install the command-line tools]: #install
[Download and import publish settings]: #import
[Create a new mobile service]: #create-service
[Get the master key]: #get-master-key
[Create a new table]: #create-table
[Register a new table script]: #register-script
[Delete an existing table]: #delete-table
[Delete an existing mobile service]: #delete-service
[Test the mobile service]: #test-service
[List mobile services]: #list-services
[List tables]: #list-tables
[Next steps]: #next-steps
[Mobile Services server script reference]: http://go.microsoft.com/fwlink/p?LinkId=262293
[Azure classic portal]: https://manage.windowsazure.com/
[nodejs-org]: http://nodejs.org/
[install-node-linux]: https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager
[mac-installer]: http://go.microsoft.com/fwlink/p?LinkId=252249
[windows-installer]: http://go.microsoft.com/fwlink/p?LinkID=275464
[reference-docs]: http://azure.microsoft.com/documentation/articles/virtual-machines-command-line-tools/#Commands_to_manage_mobile_services
[How to install the Azure Command-Line Tools for Mac and Linux]: http://go.microsoft.com/fwlink/p/?LinkId=275795
================================================
FILE: docs/mobile-services-schedule-recurring-tasks.md
================================================
# Schedule recurring jobs in Mobile Services
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
> [AZURE.SELECTOR]
- [.NET backend](mobile-services-dotnet-backend-schedule-recurring-tasks.md)
- [Javascript backend](mobile-services-schedule-recurring-tasks.md)
This topic shows you how to use the job scheduler functionality in the Azure classic portal to define server script code that is executed based on a schedule that you define. In this case, the script periodically check with a remote service, in this case Twitter, and stores the results in a new table. Some other periodic tasks that can be scheduled include:
+ Archiving old or duplicate data records.
+ Requesting and storing external data, such as tweets, RSS entries, and location information.
+ Processing or resizing stored images.
This tutorial shows you how to use the job scheduler to create a scheduled job that requests tweet data from Twitter and stores the tweets in a new Updates table.
## Register for access to Twitter v1.1 APIs and store credentials
The new Twitter v1.1 APIs requires your app to authenticate before accessing resources. First, you need to get the credentials needed to request access by using OAuth 2.0. Then, you will store them securely in the app settings for your mobile service.
1. If you haven't already done so, complete the steps in the topic [Register your apps for Twitter login with Mobile Services](./
mobile-services-how-to-register-twitter-authentication.md).
Twitter generates the credentials needed to enable you to access Twitter v1.1 APIs. You can get these credentials from the Twitter Developers website.
2. Navigate to the [Twitter Developers](http://go.microsoft.com/fwlink/p/?LinkId=268300) website, sign-in with your Twitter account credentials and select your Twitter app.
3. In the **Keys and Access Tokens** tab for the app, make a note of the following values:
+ **Consumer key**
+ **Consumer secret**
+ **Access token**
+ **Access token secret**
4. Log on to the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services**, and then click your mobile service.
5. Click the **Identity** tab, enter the **Consumer key** and **Consumer secret** values obtained from Twitter, and click **Save**.

2. Click the **Configure** tab, scroll down to **App settings** and enter a **Name** and **Value** pair for each of the following that you obtained from the Twitter site, then click **Save**.
+ `TWITTER_ACCESS_TOKEN`
+ `TWITTER_ACCESS_TOKEN_SECRET`

This stores the Twitter access token in app settings. Like the consumer credentials on the **Identity** tab, the access credentials are also stored encrypted in app settings, and you can access them in your server scripts without hard-coding them in the script file. For more information, see [App settings].
[Mobile Services server script reference]: http://go.microsoft.com/fwlink/?LinkId=262293
[Register your apps for Twitter login with Mobile Services]: ./
mobile-services-how-to-register-twitter-authentication.md
[Twitter Developers]: http://go.microsoft.com/fwlink/p/?LinkId=268300
[App settings]: http://msdn.microsoft.com/library/azure/b6bb7d2d-35ae-47eb-a03f-6ee393e170f7
## Create the new Updates table
Next, you need to create a new table in which to store tweets.
2. In the [Azure classic portal], click the **Data** tab for your mobile service, then click **+Create**.
3. In **Table name** type _Updates_, then click the check button.
## Create a new scheduled job
Now, you can create the scheduled job that accesses Twitter and stores tweet data in the new Updates table.
2. Click the **Scheduler** tab, then click **+Create**.
>[AZURE.NOTE]When you run your mobile service in Free tier, you are only able to run one scheduled job at a time. In paid tiers, you can run up to ten scheduled jobs at a time.
3. In the scheduler dialog, enter _getUpdates_ for the **Job Name**, set the schedule interval and units, then click the check button.
This creates a new job named **getUpdates**.
4. Click the new job you just created, click the **Script** tab and replace the placeholder function **getUpdates** with the following code:
var updatesTable = tables.getTable('Updates');
var request = require('request');
var twitterUrl = "https://api.twitter.com/1.1/search/tweets.json?q=%23mobileservices&result_type=recent";
// Get the service configuration module.
var config = require('mobileservice-config');
// Get the stored Twitter consumer key and secret.
var consumerKey = config.twitterConsumerKey,
consumerSecret = config.twitterConsumerSecret
// Get the Twitter access token from app settings.
var accessToken= config.appSettings.TWITTER_ACCESS_TOKEN,
accessTokenSecret = config.appSettings.TWITTER_ACCESS_TOKEN_SECRET;
function getUpdates() {
// Check what is the last tweet we stored when the job last ran
// and ask Twitter to only give us more recent tweets
appendLastTweetId(
twitterUrl,
function twitterUrlReady(url){
// Create a new request with OAuth credentials.
request.get({
url: url,
oauth: {
consumer_key: consumerKey,
consumer_secret: consumerSecret,
token: accessToken,
token_secret: accessTokenSecret
}},
function (error, response, body) {
if (!error && response.statusCode == 200) {
var results = JSON.parse(body).statuses;
if(results){
console.log('Fetched ' + results.length + ' new results from Twitter');
results.forEach(function (tweet){
if(!filterOutTweet(tweet)){
var update = {
twitterId: tweet.id,
text: tweet.text,
author: tweet.user.screen_name,
date: tweet.created_at
};
updatesTable.insert(update);
}
});
}
} else {
console.error('Could not contact Twitter');
}
});
});
}
// Find the largest (most recent) tweet ID we have already stored
// (if we have stored any) and ask Twitter to only return more
// recent ones
function appendLastTweetId(url, callback){
updatesTable
.orderByDescending('twitterId')
.read({success: function readUpdates(updates){
if(updates.length){
callback(url + '&since_id=' + (updates[0].twitterId + 1));
} else {
callback(url);
}
}});
}
function filterOutTweet(tweet){
// Remove retweets and replies
return (tweet.text.indexOf('RT') === 0 || tweet.to_user_id);
}
This script calls the Twitter query API using stored credentials to request recent tweets that contain the hashtag `#mobileservices`. Duplicate tweets and replies are removed from the results before they are stored in the table.
>[AZURE.NOTE]This sample assumes that only a few rows are inserted into the table during each scheduled run. In cases where many rows are inserted in a loop you may run out of connections when running on the Free tier. In this case, you should perform inserts in batches. For more information, see [How to: Perform bulk inserts](mobile-services-how-to-use-server-scripts.md#bulk-inserts).
6. Click **Run Once** to test the script.
This saves and executes the job while it remains disabled in the scheduler.
7. Click the back button, click **Data**, click the **Updates** table, click **Browse**, and verify that Twitter data has been inserted into the table.
8. Click the back button, click **Scheduler**, select **getUpdates**, then click **Enable**.
This enables the job to run on the specified schedule, in this case every hour.
Congratulations, you have successfully created a new scheduled job in your mobile service. This job will be executed as scheduled until you disable or modify it.
## See also
* [Mobile Services server script reference]
Learn more about registering and using server scripts.
[Register for Twitter access and store credentials]: #get-oauth-credentials
[Create the new Updates table]: #create-table
[Create a new scheduled job]: #add-job
[Next steps]: #next-steps
[Mobile Services server script reference]: http://go.microsoft.com/fwlink/?LinkId=262293
[WindowsAzure.com]: http://www.windowsazure.com/
[Azure classic portal]: https://manage.windowsazure.com/
[Register your apps for Twitter login with Mobile Services]: https://azure.microsoft.com/develop/mobile/how-to-guides/register-for-twitter-authentication
[Twitter Developers]: http://go.microsoft.com/fwlink/p/?LinkId=268300
[App settings]: http://msdn.microsoft.com/library/windowsazure/b6bb7d2d-35ae-47eb-a03f-6ee393e170f7
================================================
FILE: docs/mobile-services-sql-scale-guidance.md
================================================
# Scale mobile services backed by Azure SQL Database
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
Azure Mobile Services makes it very easy to get started and build an app that connects to a cloud-hosted backend that stores data in a SQL database. As your app grows, scaling your service instances is as simple as adjusting scale settings in the portal to add more computational and networking capacity. However, scaling the SQL database backing your service requires some proactive planning and monitoring as the service receives more load. This document will walk you through a set of best practices to ensure continued great performance of your SQL-backed mobile services.
This topic walks you through these basic sections:
1. [Diagnosing Problems](#Diagnosing)
2. [Indexing](#Indexing)
3. [Schema Design](#Schema)
4. [Query Design](#Query)
5. [Service Architecture](#Architecture)
6. [Advanced Troubleshooting](#Advanced)
## Diagnosing Problems
If you suspect your mobile service is experiencing problems under load, the first place to check is the **Dashboard** tab for your service in the [Azure classic portal]. Some of the things to verify here:
- Your usage meters including **API Calls** and **Active Devices** meters are not over quota
- **Endpoint Monitoring** status indicates service is up (only available if service is using the Standard tier and Endpoint Monitoring is enabled)
If any of the above is not true, consider adjusting your scale settings on the *Scale* tab. If that does not address the issue, you can proceed and investigate whether Azure SQL Database may be the source of the issue. The next few sections cover a few different approaches to diagnose what may be going wrong.
### Choosing the Right SQL Database Tier
It is important to understand the different database tiers you have at your disposal to ensure you've picked the right tier given your app's needs. Azure SQL Database offers three different service tiers:
- Basic
- Standard
- Premium
Here are some recommendations on selecting the right tier for your database:
- **Basic** - use at development time or for small production services where you only expect to make a single database query at a time
- **Standard** - use for production services where you expect multiple concurrent database queries
- **Premium** - use for large scale production services with many concurrent queries, high peak load, and expected low latency for every request.
For more information on when to use each tier, see [Reasons to Use the New Service Tiers]
### Analyzing Database Metrics
Once you are familiar with the different database tiers, we can explore database performance metrics to help us reason about scaling within and among the tiers.
1. Launch the [Azure classic portal].
2. On the Mobile Services tab, select the service you want to work with.
3. Select the **Configure** tab.
4. Select the **SQL Database** name in the **Database Settings** section. This will navigate to the Azure SQL Database tab in the portal.
5. Navigate to the **Monitor** tab
6. Ensure the relevant metrics are displayed by using the **Add Metrics** button. Include the following
- *CPU Percentage* (available only in Basic/Standard/Premium tiers)
- *Data IO Percentage* (available only in Basic/Standard/Premium tiers)
- *Log IO Percentage* (available only in Basic/Standard/Premium tiers)
- *Storage*
7. Inspect the metrics over the time window when your service was experiencing issues.
![Azure classic portal - SQL Database Metrics][PortalSqlMetrics]
If any metric exceeds 80% utilization for an extended period of time, this could indicate a performance problem. For more detailed information on understanding database utilization, see [Understanding Resource Use](http://msdn.microsoft.com/library/azure/dn369873.aspx#Resource).
If the metrics indicate your database is incurring high utilization, consider **scaling up the database to a higher service tier** as a first mitigation step. To immediately resolve issues, consider using the **Scale** tab for your database to scale up your database. This will result in an increase in your bill.
![Azure classic portal - SQL Database Scale][PortalSqlScale]
As soon as possible, consider these additional mitigation steps:
- **Tune your database.**
It is frequently possible to reduce database utilization and avoid having to scale to a higher tier by optimizing your database.
- **Consider your service architecture.**
Frequently your service load is not distributed evenly over time but contains "spikes" of high demand. Instead of scaling the database up to handle the spikes, and having it go underutilized during periods of low demand, it is frequently possible to adjust the service architecture to avoid such spikes, or to handle them without incurring database hits.
The remaining sections of this document contain tailored guidance to help with implementing these mitigations.
### Configuring Alerts
It is frequently useful to configure alerts for key database metrics as a proactive step to ensure you have plenty of time to react in case of resource exhaustion.
1. Navigate to the **Monitoring** tab for the database you want to set up alerts for
2. Ensure the relevant metrics are displayed as described in the previous section
3. Select the metric you want to set an alert for and select **Add Rule**
![Azure Management Portal - SQL Alert][PortalSqlAddAlert]
4. Provide a name and description for the alert
![Azure Management Portal - SQL Alert Name and Description][PortalSqlAddAlert2]
5. Specify the value to use as the alert threshold. Consider using **80%** to allow for some reaction time. Also be sure to specify an email address that you actively monitor.
![Azure Management Portal - SQL Alert Threshold and Email][PortalSqlAddAlert3]
For more information on diagnosing SQL issues, see [Advanced Diagnostics](#AdvancedDiagnosing) at the bottom of this document.
## Indexing
When you start to see problems with your query performance, the first thing you should investigate is the design of your indexes. Indexes are important because they directly affect how the SQL engine executes a query.
For instance, if you often need to look up an element by a certain field, you should consider adding an index for that column. Otherwise, the SQL engine will be forced to perform a table scan and read each physical record (or at least the query column) and the records could be substantially spread out on disk.
So, if you are frequently doing WHERE or JOIN statements on particular columns, you should make sure you index them. See the section [Creating Indexes](#CreatingIndexes) for more information.
If indexes are so great and table scans are so bad, does that mean you should index every column in your table, just to be safe? The short answer is, "probably not." Indexes take up space and have overhead themselves: every time there is an insert in a table, the index structures for each of the indexed columns need to be updated. See below for guidelines on how to choose your column indexes.
### Index Design Guidelines
As mentioned above, it's not always better to add more indexes to a table, because indexes themselves can be costly, both in terms of performance and storage overhead.
#### Query considerations
- Consider adding indexes to columns that are frequently used in predicates (e.g., WHERE clauses) and join conditions, while balancing the database considerations below.
- Write queries that insert or modify as many rows as possible in a single statement, instead of using multiple queries to update the same rows. When there is only one statement, the database engine can better optimize how it maintains indexes.
#### Database considerations
Large numbers of indexes on a table affect the performance of INSERT, UPDATE, DELETE, and MERGE statements because all indexes must be adjusted appropriately as data in the table changes.
- For **heavily updated** tables, avoid indexing heavily updated columns.
- For tables that are **not frequently updated** but that have large volumes of data, use many indexes. This can improve the performance of queries that do not modify data (such as SELECT statements) because the query optimizer will have more options for finding the best access method.
Indexing small tables may not be optimal because it can take the query optimizer longer to traverse the index searching for data than to perform a simple table scan. Therefore, indexes on small tables might never be used, but must still be maintained as data in the table changes.
### Creating Indexes
#### JavaScript backend
To set the index for a column in the JavaScript backend, do the following:
1. Open your mobile service in the [Azure classic portal].
2. Click the **Data** tab.
3. Select the table you want to modify.
4. Click the **Columns** tab.
5. Select the column. In the command bar, click **Set Index**:
![Mobile Services Portal - Set Index][SetIndexJavaScriptPortal]
You can also remove indexes within this view.
#### .NET backend
To define an index in Entity Framework, use the attribute `[Index]` on the fields that you want to index. For example:
public class TodoItem : EntityData
{
public string Text { get; set; }
[Index]
public bool Complete { get; set; }
}
For more information on indexes, see [Index Annotations in Entity Framework][]. For further tips on optimizing indexes, see [Advanced Indexing](#AdvancedIndexing) at the bottom of this document.
## Schema Design
Here are a few issues to be aware of when picking the data types for your objects, which in turn translates to the schema of your SQL database. Tuning the schema can frequently bring significant performance improvements since SQL has custom optimized ways of handling indexing and storage for different data types:
- **Use the provided ID column**. Every mobile service table comes with a default ID column configured as the primary key and has an index set on it. There is no need to create an additional ID column.
- **Use the correct datatypes in your model.** If you know a certain property of your model will be a numeric or boolean, be sure to define it that way in your model instead of as a string. In the JavaScript backend, use literals such as `true` instead of `"true"` and `5` instead of `"5"`. In the .NET backend, use the `int` and `bool` types when you declare the properties of your model. This enables SQL to create the correct schema for those types, which makes queries more efficient.
## Query Design
Here are some guidelines to consider when querying the database:
- **Always execute join operations in the database.** Frequently you will need to combine records from two or more tables where the records being combined share a common field (also known as a *join*). This operation can be inefficient if performed incorrectly since it may involve pulling down all the entities from both tables and then iterating through all of them. This kind of operation is best left to the database itself, but it is sometimes easy to mistakenly perform it on the client or in the mobile service code.
- Don't perform joins in your app code
- Don't perform joins in your mobile service code. When using the JavaScript backend, be aware that the [table object](http://msdn.microsoft.com/library/windowsazure/jj554210.aspx) does not handle joins. Be sure to use the [mssql object](http://msdn.microsoft.com/library/windowsazure/jj554212.aspx) directly to ensure the join happens in the database. For more information, see [Join relational tables](mobile-services-how-to-use-server-scripts.md#joins). If using the .NET backend and querying via LINQ, joins are automatically handled at the database level by Entity Framework.
- **Implement paging.** Querying the database can sometimes result in a large number of records being returned to the client. To minimize the size and latency of operations, consider implementing paging.
- By default your mobile service will limit any incoming queries to a page size of 50, and you can manually request up to 1,000 records. For more information, see "Return data in pages" for [Windows Store](mobile-services-windows-dotnet-how-to-use-client-library.md#paging), [iOS](mobile-services-ios-how-to-use-client-library.md#paging), [Android](mobile-services-android-how-to-use-client-library.md#paging), [HTML/JavaScript](mobile-services-html-how-to-use-client-library#paging), and [Xamarin](partner-xamarin-mobile-services-how-to-use-client-library.md#paging).
- There is no default page size for queries made from your mobile service code. If your app does not implement paging, or as a defensive measure, consider applying default limits to your queries. In the JavaScript backend, use the **take** operator on the [query object](http://msdn.microsoft.com/library/azure/jj613353.aspx). If using the .NET backend, consider using the [Take method] as part of your LINQ query.
For more information on improving query design, including how to analyze query plans, see [Advanced Query Design](#AdvancedQuery) at the bottom of this document.
## Service Architecture
Imagine a scenario where you are about to send a push notification to all your customers to check out some new content in your app. As they tap on the notification, the app launches, which possibly triggers a call to your mobile service and a query execution against your SQL database. As potentially millions of customers take this action over the span of just a few minutes, this will generate a surge of SQL load, which may be orders of magnitude higher than your app's steady state load. This could be addressed by scaling your app to a higher SQL tier during the spike and then scaling it back down, however that solution requires manual intervention and comes with increased cost. Frequently slight tweaks in your mobile service architecture can significantly balance out the load clients drive to your SQL database and eliminate problematic spikes in demand. These modifications can often be implemented easily with minimal impact to your customer's experience. Here are some examples:
- **Spread out the load over time.** If you control the timing of certain events (for example, a broadcast push notification), which are expected to generate a spike in demand, and the timing of those events is not critical, consider spreading them out over time. In the example above, perhaps it is acceptable for your app customers to get notified of the new app content in batches over the span of a day instead of nearly simultaneously. Consider batching up your customers into groups which will allow staggered delivery to each batch. If using Notification Hubs, applying an additional tag to track the batch, and then delivering a push notification to that tag provides an easy way to implement this strategy. For more information on tags, see [Use Notification Hubs to send breaking news](https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-windows-notification-dotnet-push-xplat-segmented-wns/).
- **Use Blob and Table Storage whenever appropriate.** Frequently the content that the customers will view during the spike is fairly static and doesn't need to be stored in a SQL database since you are unlikely to need relational querying capabilities over that content. In that case, consider storing the content in Blob or Table Storage. You can access public blobs in Blob Storage directly from the device. To access blobs in a secure way or use Table Storage, you will need to go through a Mobile Services Custom API in order to protect your storage access key. For more information, see [Upload images to Azure Storage by using Mobile Services](mobile-services-dotnet-backend-windows-universal-dotnet-upload-data-blob-storage.md).
- **Use an in-memory cache**. Another alternative is to store data, which would commonly be accessed during a traffic spike, in an in-memory cache such as [Azure Cache](https://azure.microsoft.com/services/cache/). This means incoming requests would be able to fetch the information they need from memory, instead of repeatedly querying the database.
## Advanced Troubleshooting
This section covers some more advanced diagnostic tasks, which may be useful if the steps so far have not addressed the issue fully.
### Prerequisites
To perform some of the diagnostic tasks in this section, you need access to a management tool for SQL databases such as **SQL Server Management Studio** or the management functionality built into the **Azure classic portal**.
SQL Server Management Studio is a free Windows application, which offers the most advanced capabilities. If you do not have access to a Windows machine (for example if you are using a Mac), consider provisioning a Virtual Machine in Azure as shown in [Create a Virtual Machine Running Windows Server](https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-windows-hero-tutorial/) and then connecting remotely to it. If you intend to use the VM primarily for the purpose of running SQL Server Management Studio, a **Basic A0** (formerly "Extra Small") instance should be sufficient.
The Azure classic portal offers a built-in management experience, which is more limited, but is available without a local install.
The following steps walk you through obtaining the connection information for the SQL database backing your mobile service and then using either of the two tools to connect to it. You may pick whichever tool you prefer.
#### Obtain SQL connection information
1. Launch the [Azure classic portal].
2. On the Mobile Services tab, select the service you want to work with.
3. Select the **Configure** tab.
4. Select the **SQL Database** name in the **Database Settings** section. This will navigate to the Azure SQL Database tab in the portal.
5. Select **Set up Azure firewall rules for this IP address**.
6. Make a note of the server address in the **Connect to your database** section, for example: *mcml4otbb9.database.windows.net*.
#### SQL Server Management Studio
1. Navigate to [SQL Server Editions - Express](http://www.microsoft.com/server-cloud/products/sql-server-editions/sql-server-express.aspx)
2. Find the **SQL Server Management Studio** section and select the **Download** button underneath.
3. Complete the setup steps until you can successfully run the application:
![SQL Server Management Studio][SSMS]
4. In the **Connect to Server** dialog enter the following values
- Server name: *server address you obtained earlier*
- Authentication: *SQL Server Authentication*
- Login: *login you picked when creating server*
- Password: *password you picked when creating server*
5. You should now be connected.
#### SQL Database Management Portal
1. On Azure SQL Database tab for your database, select the **Manage** button
2. Configure the connection with the following values
- Server: *should be pre-set to the right value*
- Database: *leave blank*
- Username: *login you picked when creating server*
- Password: *password you picked when creating server*
3. You should now be connected.
![Azure classic portal - SQL Database][PortalSqlManagement]
### Advanced Diagnostics
A lot of diagnostic tasks can be completed easily right in the **Azure classic portal**, however some advanced diagnostic tasks are only possible via **SQL Server Management Studio** or the **SQL Database Management Portal**. We will take advantage of dynamic management views, a set of views populated automatically with diagnostic information about your database. This section provides a set of queries we can run against these views to examine various metrics. For more information, see [Monitoring SQL Database Using Dynamic Management Views][].
After completing the steps in the previous section to connect to your database in SQL Server Management Studio, select your database in **Object Explorer**. Expanding **Views** and then **System Views** reveals a list of the management views. To execute the queries below, select **New Query**, while you have selected your database in **Object Explorer**, then paste the query and select **Execute**.
![SQL Server management Studio - dynamic management views][SSMSDMVs]
Alternatively if you are using the SQL Database Management Portal, first select your database and then pick **New Query**.
![SQL Database Management Portal - new query][PortalSqlManagementNewQuery]
To execute any of the queries below, paste it into the window and select **Run**.
![SQL Database Management Portal - run query][PortalSqlManagementRunQuery]
#### Advanced Metrics
The management portal makes certain metrics readily available if using the Basic, Standard, and Premium tiers. It is easy to obtain these and other metrics using the **[sys.resource\_stats](http://msdn.microsoft.com/library/dn269979.aspx)** management view, regardless of what tier you're using. Consider the following query:
SELECT TOP 10 *
FROM sys.resource_stats
WHERE database_name = 'todoitem_db'
ORDER BY start_time DESC
> [AZURE.NOTE]
> Please execute this query on the **master** database on your server, the **sys.resource\_stats** view is only present on that database.
The result will contain the following useful metrics: CPU (% of tier limit), Storage (megabytes), Physical Data Reads (% of tier limit), Log Writes (% of tier limit), Memory (% of tier limit), Worker Count, Session Count, etc.
#### SQL connectivity events
The **[sys.event\_log](http://msdn.microsoft.com/library/azure/jj819229.aspx)** view contains the details of connectivity-related events.
select * from sys.event_log
where database_name = 'todoitem_db'
and event_type like 'throttling%'
order by start_time desc
> [AZURE.NOTE]
> Please execute this query on the **master** database on your server, the **sys.event\_log** view is only present on that database.
### Advanced Indexing
A table or view can contain the following types of indexes:
- **Clustered**. A clustered index specifies how records are physically stored on disk. There must be only one clustered index per table, because the data rows themselves can be sorted in only one order.
- **Nonclustered**. Nonclustered indexes are stored separately from data rows and are used to do a lookup based on the index value. All nonclustered indexes on a table use the key values from the clustered index as lookup key.
To provide a real-world analogy: consider a book or a technical manual. The contents of each page are a record, the page number is the clustered index, and the topic index in the back of the book is a nonclustered index. Each entry in the topic index points to the clustered index, the page number.
> [AZURE.NOTE]
> By default, the JavaScript backend of Azure Mobile Services sets **\_createdAt** as the clustered index. If you remove this column, or if you want a different clustered index, be sure to follow the [clustered index design guidelines](#ClusteredIndexes) below. In the .NET backend, the class `EntityData` defines `CreatedAt` as a clustered index using the annotation `[Index(IsClustered = true)]`.
#### Clustered index design guidelines
Every table should have a clustered index on the column (or columns, in the case of a composite key) with the following properties:
- Narrow - uses a small datatype, or is a [composite key][Primary and Foreign Key Constraints] of a small number of narrow columns
- Unique, or mostly unique
- Static - value is not frequently changed
- Ever-increasing
- (Optional) Fixed-width
- (Optional) nonnull
The reason for the **narrow** property is that all other indexes on a table use the key values from the clustered index as lookup keys. In the example of a topic index at the back of a book, the clustered index is a page number and is a small number. If the chapter title were instead included in the clustered index, then the topic index would itself be much longer, because the key value would then be (chapter name, page number).
The key should be **static** and **ever-increasing** to avoid having to maintain the physical location of the records (which means either moving records physically, or potentially fragmenting storage by splitting the pages where the records are stored).
The clustered index will be most valuable for queries that do the following:
- Return a range of values by using operators such as BETWEEN, >, >=, <, and <=.
- After the row with the first value is found by using the clustered index, rows with subsequent indexed values are guaranteed to be physically adjacent.
- Use JOIN clauses; typically these are foreign key columns.
- Use ORDER BY, or GROUP BY clauses.
- An index on the columns specified in the ORDER BY or GROUP BY clause may remove the need for the Database Engine to sort the data, because the rows are already sorted. This improves query performance.
#### Creating clustered indexes in Entity Framework
To set the clustered index in the .NET backend using Entity Framework, set the `IsClustered` property of the annotation. For example, this is the definition of `CreatedAt` in `Microsoft.WindowsAzure.Mobile.Service.EntityData`:
[Index(IsClustered = true)]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[TableColumnAttribute(TableColumnType.CreatedAt)]
public DateTimeOffset? CreatedAt { get; set; }
#### Creating indexes in the database schema
For the JavaScript backend, you can only modify the clustered index of a table by changing the database schema directly, either through SQL Server Management Studio or the Azure SQL Database Portal.
The following guides describe how to set a clustered or nonclustered index by modifying the database schema directly:
- [Creating and Modifying PRIMARY KEY Constraints][]
- [Create Nonclustered Indexes][]
- [Create Clustered Indexes][]
- [Create Unique Indexes][]
#### Find top N missing indexes
You can write SQL queries on dynamic management views that will tell you more detailed information about the resource usage of individual queries or give you heuristics on what indexes to add. The following query determines which 10 missing indexes would produce the highest anticipated cumulative improvement, in descending order, for user queries.
SELECT TOP 10 *
FROM sys.dm_db_missing_index_group_stats
ORDER BY avg_total_user_cost * avg_user_impact * (user_seeks + user_scans)
DESC;
The following example query runs a join across these tables to get a list of the columns that should be part of each missing index and calculates an 'index advantage' to determine if the given index should be considered:
SELECT * from
(
SELECT
(user_seeks+user_scans) * avg_total_user_cost * (avg_user_impact * 0.01) AS index_advantage, migs.*
FROM sys.dm_db_missing_index_group_stats migs
) AS migs_adv,
sys.dm_db_missing_index_groups mig,
sys.dm_db_missing_index_details mid
WHERE
migs_adv.group_handle = mig.index_group_handle and
mig.index_handle = mid.index_handle
AND migs_adv.index_advantage > 10
ORDER BY migs_adv.index_advantage DESC;
For more information, see [Monitoring SQL Database Using Dynamic Management Views][] and [Missing Index Dynamic Management Views][].
### Advanced Query Design
Frequently it's difficult to diagnose what queries are most expensive for the database.
#### Finding top N queries
The following example returns information about the top five queries ranked by average CPU time. This example aggregates the queries according to their query hash, so that logically equivalent queries are grouped by their cumulative resource consumption.
SELECT TOP 5 query_stats.query_hash AS "Query Hash",
SUM(query_stats.total_worker_time) / SUM(query_stats.execution_count) AS "Avg CPU Time",
MIN(query_stats.statement_text) AS "Statement Text"
FROM
(SELECT QS.*,
SUBSTRING(ST.text, (QS.statement_start_offset/2) + 1,
((CASE statement_end_offset
WHEN -1 THEN DATALENGTH(st.text)
ELSE QS.statement_end_offset END
- QS.statement_start_offset)/2) + 1) AS statement_text
FROM sys.dm_exec_query_stats AS QS
CROSS APPLY sys.dm_exec_sql_text(QS.sql_handle) as ST) as query_stats
GROUP BY query_stats.query_hash
ORDER BY 2 DESC;
For more information, see [Monitoring SQL Database Using Dynamic Management Views][]. In addition to executing the query, the **SQL Database Management Portal** gives you a nice shortcut to see this data, by selecting **Summary** for your database and then selecting **Query Performance**:
![SQL Database Management Portal - query performance][PortalSqlManagementQueryPerformance]
#### Analyzing the query plan
Once you have identified expensive queries or if you are about to deploy code using new queries and you would like to investigate their performance, the tooling offers great support for analyzing the **query plan**. The query plan enables you to see what operations take up the builk of CPU time and IO resources when a given SQL query runs. To analyze the query plan in **SQL Server Management Studio**, use the highlighted toolbar buttons.
![SQL Server Management Studio - query plan][SSMSQueryPlan]
To analyze the query plan in the **SQL Database Management Portal**, use the highlighted toolbar buttons.
![SQL Database Management Portal - query plan][PortalSqlManagementQueryPlan]
## See Also
- [Azure SQL Database Documentation][]
- [Azure SQL Database performance and scaling][]
- [Troubleshooting Azure SQL Database][]
### Indexing
- [Index Basics][]
- [General Index Design Guidelines][]
- [Unique Index Design Guidelines][]
- [Clustered Index Design Guidelines][]
- [Primary and Foreign Key Constraints][]
- [How much does that key cost?][]
### Entity Framework
- [Performance Considerations for Entity Framework 5][]
- [Code First Data Annotations][]
[SSMS]: ./media/mobile-services-sql-scale-guidance/1.png
[PortalSqlManagement]: ./media/mobile-services-sql-scale-guidance/2.png
[PortalSqlMetrics]: ./media/mobile-services-sql-scale-guidance/3.png
[PortalSqlScale]: ./media/mobile-services-sql-scale-guidance/4.png
[PortalSqlAddAlert]: ./media/mobile-services-sql-scale-guidance/5.png
[PortalSqlAddAlert2]: ./media/mobile-services-sql-scale-guidance/6.png
[PortalSqlAddAlert3]: ./media/mobile-services-sql-scale-guidance/7.png
[SetIndexJavaScriptPortal]: ./media/mobile-services-sql-scale-guidance/set-index-portal-ui.png
[SSMSDMVs]: ./media/mobile-services-sql-scale-guidance/8.png
[PortalSqlManagementNewQuery]: ./media/mobile-services-sql-scale-guidance/9.png
[PortalSqlManagementRunQuery]: ./media/mobile-services-sql-scale-guidance/10.png
[PortalSqlManagementQueryPerformance]: ./media/mobile-services-sql-scale-guidance/11.png
[SSMSQueryPlan]: ./media/mobile-services-sql-scale-guidance/12.png
[PortalSqlManagementQueryPlan]: ./media/mobile-services-sql-scale-guidance/13.png
[Azure classic portal]: http://manage.windowsazure.com
[Azure SQL Database Documentation]: http://azure.microsoft.com/documentation/services/sql-database/
[Managing SQL Database using SQL Server Management Studio]: http://go.microsoft.com/fwlink/p/?linkid=309723&clcid=0x409
[Monitoring SQL Database Using Dynamic Management Views]: http://go.microsoft.com/fwlink/p/?linkid=309725&clcid=0x409
[Azure SQL Database performance and scaling]: http://go.microsoft.com/fwlink/p/?linkid=397217&clcid=0x409
[Troubleshooting Azure SQL Database]: http://msdn.microsoft.com/library/azure/ee730906.aspx
[Reasons to Use the New Service Tiers]:http://msdn.microsoft.com/library/azure/dn369873.aspx#Reasons
[Take method]:http://msdn.microsoft.com/library/vstudio/bb503062(v=vs.110).aspx
[Creating and Modifying PRIMARY KEY Constraints]: http://technet.microsoft.com/library/ms181043(v=sql.105).aspx
[Create Clustered Indexes]: http://technet.microsoft.com/library/ms186342(v=sql.120).aspx
[Create Unique Indexes]: http://technet.microsoft.com/library/ms187019.aspx
[Create Nonclustered Indexes]: http://technet.microsoft.com/library/ms189280.aspx
[Primary and Foreign Key Constraints]: http://msdn.microsoft.com/library/ms179610(v=sql.120).aspx
[Index Basics]: http://technet.microsoft.com/library/ms190457(v=sql.105).aspx
[General Index Design Guidelines]: http://technet.microsoft.com/library/ms191195(v=sql.105).aspx
[Unique Index Design Guidelines]: http://technet.microsoft.com/library/ms187019(v=sql.105).aspx
[Clustered Index Design Guidelines]: http://technet.microsoft.com/library/ms190639(v=sql.105).aspx
[Missing Index Dynamic Management Views]: http://technet.microsoft.com/library/ms345421.aspx
[Performance Considerations for Entity Framework 5]: http://msdn.microsoft.com/data/hh949853
[Code First Data Annotations]: http://msdn.microsoft.com/data/jj591583.aspx
[Index Annotations in Entity Framework]:http://msdn.microsoft.com/data/jj591583.aspx#Index
[How much does that key cost?]: http://www.sqlskills.com/blogs/kimberly/how-much-does-that-key-cost-plus-sp_helpindex9/
================================================
FILE: docs/mobile-services-store-scripts-source-control.md
================================================
# Store your mobile service project code in source control
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
> [AZURE.SELECTOR]
- [.NET backend](mobile-services-dotnet-backend-store-code-source-control.md)
- [Javascript backend](mobile-services-store-scripts-source-control.md)
This topic shows you how to use the source control provided by Azure Mobile Services to store your server scripts. Scripts and other JavaScript backend code files can be promoted from your local Git repository to your production mobile service. It also shows how to define shared code that can be required by multiple scripts and how to use the package.json file to add Node.js modules to your mobile service.
To complete this tutorial, you must have already created a mobile service by completing the [Get started with Mobile Services] tutorial.
## Enable source control in your mobile service
To be able to store app data in the new mobile service, you must first create a new table in the associated SQL Database instance.
1. Log on to the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services**, click your mobile service, then click the **Dashboard** tab.
2. (Optional) If you have already set the Mobile Services or Websites source control credentials for your Azure subscription, then you can skip down to step 4. Otherwise, click **Set up source control** under **Quick glance** and click **Yes** to confirm.

3. Supply a **User name**, **New password**, confirm the password, then click the check button.
The Git repository is created in your mobile service. Make a note of the credentials you just supplied; you will use them to access this and other Mobile Services repositories in your subscription.
4. Click the **Configure** tab and notice the **Source control** fields.

The URL of the Git repository is displayed. You will use this URL to clone the repository to your local computer.
With source control enabled in your mobile service, you can use Git to clone the repository to your local computer.
## Install Git and create the local repository
1. Install Git on your local computer.
The steps required to install Git vary between operating systems. See [Installing Git] for operating system specific distributions and installation guidance.
> [AZURE.NOTE]
> On some operating systems, both a command-line and GUI version of Git are available. The instructions provided in this article use the command-line version.
2. Open a command-line, such as **GitBash** (Windows) or **Bash** (Unix Shell). On OS X systems you can access the command-line through the **Terminal** application.
3. From the command line, change to the directory where you will store your scripts. For example, `cd SourceControl`.
4. Use the following command to create a local copy of your new Git repository, replacing `` with the URL of the Git repository for your mobile service:
git clone
5. When prompted, type in the user name and password that you set when you enabled source control in your mobile service. After successful authentication, you will see a series of responses like this:
remote: Counting objects: 8, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 8 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (8/8), done.
6. Browse to the directory from which you ran the `git clone` command, and notice the following directory structure:
![4][4]
In this case, a new directory is created with the name of the mobile service, which is the local repository for the data service.
7. Open the .\service\table subfolder and notice that it contains a TodoItem.json file, which is a JSON representation of the operation permissions on the TodoItem table.
When server scripts have been defined on this table, you will also have one or more files named TodoItem._<operation>_.js that contain the scripts for the given table operation. Scheduler and custom API scripts are maintained in separate folders with those respective names. For more information, see [Source control].
Now that you have created your local repository, you can make changes to server scripts and push the changes back to the mobile service.
## Deploy updated script files to your mobile service
1. Browse to the .\service\table subfolder, and if a file todoitem.insert.js files doesn't already exist, create it now.
2. Open the new file todoitem.insert.js in a text editor and paste in the following code and save your changes:
function insert(item, user, request) {
request.execute();
console.log(JSON.stringify(item, null, 4));
}
This code simply writes the inserted item to the log. If this file already contains code, simply add some valid JavaScript code to this file, such as a call to `console.log()`, then save your changes.
3. In the Git command prompt, type the following command to start tracking the new script file:
$ git add .
4. Type the following command to commit changes:
$ git commit -m "updated the insert script"
5. Type the following command to upload the changes to the remote repository:
$ git push origin master
You should see a series of commands that indicates that the commit is deployed to the mobile service.
6. Back in the [Azure classic portal], click the **Data** tab, then click the **TodoItem** table, click **Script**, then select the **Insert** operation. Notice that the displayed insert operation script is the same as the JavaScript code that you just uploaded to the repository.
## Leverage shared code and Node.js modules in your server scripts
Mobile Services provides access to the full set of core Node.js modules, which you can use in your code by using the **require** function. Your mobile service can also use Node.js modules that are not part of the core Node.js package, and you can even define your own shared code as Node.js modules. For more information about creating modules, see [Modules] in the Node.js API reference documentation.
The recommended way to add Node.js modules to your mobile service is by adding references to the service's package.json file. Next, you will add the [node-uuid] Node.js module to your mobile service by updating the package.json file. When the update is pushed to Azure, the mobile service is restarted and the module is installed. This module is then used to generate a new GUID value for the **uuid** property on inserted items.
2. Navigate to the `.\service` folder of your local Git repository, and open the package.json file in a text editor, and add the following field to the **dependencies** object:
"node-uuid": "~1.4.3"
>[AZURE.NOTE]This update to the package.json file will cause a restart in your mobile service after the commit is pushed.
4. Now browse to the .\service\table subfolder, open the todoitem.insert.js file and modify it as follows:
function insert(item, user, request) {
var uuid = require('node-uuid');
item.uuid = uuid.v1();
request.execute();
console.log(item);
}
This code adds a uuid column to the table, populating it with unique GUID identifiers.
5. As in the previous section, type the following command in the Git command prompt:
$ git add .
$ git commit -m "added node-uuid module"
$ git push origin master
This adds the new file, commits your changes, and pushes the new node-uuid module and changes to the todoitem.insert.js script to your mobile service.
## Next steps
Now that you have completed this tutorial you know how to store your scripts in source control. Consider learning more about working with server scripts and with custom APIs:
+ [Work with server scripts in Mobile Services]
Shows how to work with server scripts, job scheduler, and custom APIs.
[Enable source control in your mobile service]: #enable-source-control
[Install Git and create the local repository]: #clone-repo
[Deploy updated script files to your mobile service]: #deploy-scripts
[Leverage shared code and Node.js modules in your server scripts]: #use-npm
[4]: ./media/mobile-services-store-scripts-source-control/mobile-source-local-repo.png
[5]: ./media/mobile-services-store-scripts-source-control/mobile-portal-data-tables.png
[6]: ./media/mobile-services-store-scripts-source-control/mobile-insert-script-source-control.png
[Git website]: http://git-scm.com
[Source control]: http://msdn.microsoft.com/library/windowsazure/c25aaede-c1f0-4004-8b78-113708761643
[Installing Git]: http://git-scm.com/book/en/Getting-Started-Installing-Git
[Get started with Mobile Services]: mobile-services-ios-get-started.md
[Work with server scripts in Mobile Services]: mobile-services-how-to-use-server-scripts.md
[Azure classic portal]: https://manage.windowsazure.com/
[Modules]: http://nodejs.org/api/modules.html
[node-uuid]: https://npmjs.org/package/node-uuid
================================================
FILE: docs/mobile-services-using-soft-delete.md
================================================
# Using soft delete in Mobile Services
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
## Overview
Tables created with either the JavaScript or .NET backend can optionally have soft delete enabled. When using soft delete, a new column called *\__deleted* of [SQL bit type] is added to the database. With soft delete enabled, a delete operation does not physically delete rows from the database, but rather sets the value of the deleted column to TRUE.
When querying records on a table with soft delete enabled, deleted rows are not returned in the query by default. In order to request these rows, you must pass a query parameter *\__includeDeleted=true* in your [REST Query operation](http://msdn.microsoft.com/library/azure/jj677199.aspx). In the .NET client SDK, you can also use the helper method `IMobileServiceTable.IncludeDeleted()`.
Soft delete support for the .NET backend first released with version 1.0.402 of the Microsoft Azure Mobile Services .NET Backend. The latest NuGet packages are available here, [Microsoft Azure Mobile Services .NET Backend](http://go.microsoft.com/fwlink/?LinkId=513165).
Some of the potential benefits of using soft delete:
* When using the [Offline data Sync for Mobile Services] feature, the client SDK automatically queries for deleted records and removes them from the local database. Without soft delete enabled, you need to write additional code on the backend so that the client SDK knows which records to remove from the local store. Otherwise, the client local store and backend will be inconsistent with regard to these deleted records and the client method `PurgeAsync()` must be called to clear the local store.
* Some applications have a business requirement to never physically delete data, or to delete data only after it has been audited. The soft delete feature can be useful in this scenario.
* Soft delete can be used to implement an "undelete" feature, so that data deleted by accident can be recovered.
However, soft deleted records take up space in the database, so you should consider creating a scheduled job to periodically hard delete the soft deleted records. For an example of this, see [Using soft delete with the .NET backend](#using-with-dotnet) and [Using soft delete with the JavaScript backend](#using-with-javascript). Your client code should also periodically call `PurgeAsync()` so that these hard deleted records do not remain in the device's local data store.
## Enabling soft delete for the .NET backend
Soft delete support for the .NET backend first released with version 1.0.402 of the Microsoft Azure Mobile Services .NET Backend. The latest NuGet packages are available here, [Microsoft Azure Mobile Services .NET Backend](http://go.microsoft.com/fwlink/?LinkId=513165).
The following steps guide you on how to enable soft delete for a .NET backend mobile service.
1. Open your .NET backend mobile service project in Visual Studio.
2. Right click the .NET backend project and click **Manage NuGet Packages**.
3. In the package manager dialog, click **Nuget.org** under updates and install version 1.0.402 or later of the [Microsoft Azure Mobile Services .NET Backend](http://go.microsoft.com/fwlink/?LinkId=513165) NuGet packages.
3. In Solution Explorer for Visual Studio, expand the **Controllers** node under your .NET backend project and open your controller source for. For example, *TodoItemController.cs*.
4. In the `Initialize()` method of your controller, pass the `enableSoftDelete: true` parameter to the EntityDomainManager constructor.
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
MobileService1Context context = new MobileService1Context();
DomainManager = new EntityDomainManager(context, Request, Services, enableSoftDelete: true);
}
## Enabling soft delete for the JavaScript backend
If you are creating a new table for your mobile service, you can enable soft delete on the table creation page.
![][2]
To enable soft delete on an existing table in the JavaScript backend:
1. In the [Azure classic portal], click your mobile service. Then click the Data tab.
2. On the data page, click to select the desired table. Then click the **Enable Soft Delete** button in the command bar. If the table already has soft delete enabled, this button will not appear but you will be able to see the *\__deleted* column when clicking the **Browse** or **Columns** tab for the table.
![][0]
To disable soft delete for your table, click the **Columns** tab and then click the *\__deleted* column and the **Delete** button.
![][1]
## Using soft delete with the .NET backend
The following scheduled job purges soft deleted records that are more than a month old:
public class SampleJob : ScheduledJob
{
private MobileService1Context context;
protected override void Initialize(ScheduledJobDescriptor scheduledJobDescriptor,
CancellationToken cancellationToken)
{
base.Initialize(scheduledJobDescriptor, cancellationToken);
context = new MobileService1Context();
}
public override Task ExecuteAsync()
{
Services.Log.Info("Purging old records");
var monthAgo = DateTimeOffset.UtcNow.AddDays(-30);
var toDelete = context.TodoItems.Where(x => x.Deleted == true && x.UpdatedAt <= monthAgo).ToArray();
context.TodoItems.RemoveRange(toDelete);
context.SaveChanges();
return Task.FromResult(true);
}
}
To learn more about schedule jobs with .NET backend Mobile Services, see: [Schedule recurring jobs with JavaScript backend Mobile Services](mobile-services-dotnet-backend-schedule-recurring-tasks.md)
## Using soft delete with the JavaScript backend
You use table scripts to add logic around the soft delete feature with JavaScript backend mobile services.
To detect an undelete request, use the property "undelete" in your update table script:
function update(item, user, request) {
if (request.undelete) { /* any undelete specific code */; }
}
To include deleted records in query result in a script, set the "includeDeleted" parameter to true:
tables.getTable('softdelete_scenarios').read({
includeDeleted: true,
success: function (results) {
request.respond(200, results)
}
});
To retrieve deleted records via an HTTP request, add the query parameter "__includedeleted=true":
http://youservice.azure-mobile.net/tables/todoitem?__includedeleted=true
### Sample scheduled job for purging soft deleted records.
This is a sample scheduled job that deletes records that were updated prior to a particular date:
function purgedeleted() {
mssql.query('DELETE FROM softdelete WHERE __deleted=1', {
success: function(results) {
console.log(results);
},
error: function(err) {
console.log("error is: " + err);
}});
}
To learn more about scheduled jobs with JavaScript backend Mobile Services, see: [Schedule recurring jobs with JavaScript backend Mobile Services](mobile-services-schedule-recurring-tasks.md).
[0]: ./media/mobile-services-using-soft-delete/enable-soft-delete-button.png
[1]: ./media/mobile-services-using-soft-delete/disable-soft-delete.png
[2]: ./media/mobile-services-using-soft-delete/enable-soft-delete-new-table.png
[SQL bit type]: http://msdn.microsoft.com/library/ms177603.aspx
[Offline data Sync for Mobile Services]: mobile-services-windows-store-dotnet-get-started-offline-data.md
[Azure classic portal]: https://manage.windowsazure.com/
================================================
FILE: docs/mobile-services-windows-phone-get-started-data.md
================================================
# Add Mobile Services to an existing app
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-data.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-windows-phone-get-started-data.md)
- [(Android | Javascript)](mobile-services-android-get-started-data.md)
## Overview
This topic shows you how to use Azure Mobile Services to leverage data in a Windows Phone 8 app. In this tutorial, you will download an app that stores data in memory, create a new mobile service, integrate the mobile service with the app, and then login to the [Azure classic portal] to view changes to data made when running the app.
You can also see Nick Harris demonstrate this in the following video:
>[AZURE.VIDEO mobile-get-started-with-data-windows-phone]
## Prerequisites
+ Visual Studio 2012 Express for Windows Phone 8 and the [Windows Phone 8 SDK] running on Windows 8. To complete this tutorial to create a Windows Phone 8.1 app, you must use Visual Studio 2013 Update 2, or a later version.
+ An Azure account. If you don't have an account, you can create a free trial account in just a couple of minutes. For details, see [Azure Free Trial](https://azure.microsoft.com/pricing/free-trial/?WT.mc_id=A756A2826&returnurl=http%3A%2F%2Fazure.microsoft.com%2Farticles%2Fdocumentation%2Fmobile-services-windows-phone-get-started-data%2F).
## Download the GetStartedWithData project
This tutorial is built on the [GetStartedWithData app][Developer Code Samples site], which is a Windows Phone Silverlight 8 app project.
1. Download the GetStartedWithData sample app project from the [Developer Code Samples site].
>[AZURE.NOTE]To create a Windows Phone Silverlght 8.1 app, just change the target OS in the downloaded Windows Phone Silverlight 8 app project to Windows Phone 8.1. To create a Windows Phone Store app, download the [Windows Phone Store app version](http://go.microsoft.com/fwlink/p/?LinkId=397372) of the GetStartedWithData sample app project.
2. In Visual Studio, open the downloaded project and examine the MainPage.xaml.cs file.
Notice that added **TodoItem** objects are stored in an in-memory **ObservableCollection<TodoItem>**.
3. Press the **F5** key to rebuild the project and start the app.
4. In the app, type some text in the text box, then click the **Save** button.
![][0]
Notice that the saved text is displayed in the list below.
## Create a new mobile service in the Azure classic portal
Next, you will create a new mobile service to replace the in-memory list for data storage. Follow these steps to create a new mobile service.
1. Log into the [Azure classic portal](https://manage.windowsazure.com/).
2. At the bottom of the navigation pane, click **+NEW**.

3. Expand **Compute** and **Mobile Service**, then click **Create**.

This displays the **New Mobile Service** dialog.
4. In the **Create a mobile service** page, select **Create a free 20 MB SQL Database**, then type a subdomain name for the new mobile service in the **URL** textbox and wait for name verification. Once name verification completes, click the right arrow button to go to the next page.

This displays the **Specify database settings** page.
> [AZURE.NOTE] As part of this tutorial, you create a new SQL Database instance and server. You can reuse this new database and administer it as you would any other SQL Database instance. If you already have a database in the same region as the new mobile service, you can instead choose **Use existing Database** and then select that database. The use of a database in a different region is not recommended because of additional bandwidth costs and higher latencies.
5. In **Name**, type the name of the new database, then type **Login name**, which is the administrator login name for the new SQL Database server, type and confirm the password, and click the check button to complete the process.

> [AZURE.NOTE] When the password that you supply does not meet the minimum requirements or when there is a mismatch, a warning is displayed.
>
> We recommend that you make a note of the administrator login name and password that you specify; you will need this information to reuse the SQL Database instance or the server in the future.
You have now created a new mobile service that can be used by your mobile apps. Next, you will add a new table in which to store app data. This table will be used by the app in place of the in-memory collection.
## Add a new table to the mobile service
To be able to store app data in the new mobile service, you must first create a new table in the associated SQL Database instance.
1. In the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services**, and then click the mobile service that you just created.
2. Click the **Data** tab, then click **+Create**.
This displays the **Create new table** dialog.
3. In **Table name** type _TodoItem_, then click the check button. This creates a new storage table **TodoItem** with the default permissions set. This means that anyone with the application key, which is distributed with your app, can access and change data in the table.
>[AZURE.NOTE] The same table name is used in Mobile Services quickstart. However, each table is created in a schema that is specific to a given mobile service. This is to prevent data collisions when multiple mobile services use the same database.
4. Click the new **TodoItem** table and verify that there are no data rows.
5. Click the **Columns** tab. Verify that the following default columns are automatically created for you:
Column Name
Type
Index
id
string
Indexed
__createdAt
date
Indexed
__updatedAt
date
-
__version
timestamp (MSSQL)
-
This is the minimum requirement for a table in Mobile Services.
> [AZURE.NOTE] When dynamic schema is enabled on your mobile service, new columns are created automatically when JSON objects are sent to the mobile service by an insert or update operation.
You are now ready to use the new mobile service as data storage for the app.
## Update the app to use the mobile service for data access
Now that your mobile service is ready, you can update the app to store items in Mobile Services instead of the local collection.
1. In **Solution Explorer** in Visual Studio, right-click the project name, and then select **Manage NuGet Packages**.
2. In the left pane, select the **Online** category, search for `WindowsAzure.MobileServices`, click **Install** on the **Azure Mobile Services** package, then accept the license agreement.
![][7]
This adds the Mobile Services client library to the project.
3. In the [Azure classic portal], click **Mobile Services**, and then click the mobile service you just created.
4. Click the **Dashboard** tab and make a note of the **Site URL**, then click **Manage keys** and make a note of the **Application key**.
![][8]
You will need these values when accessing the mobile service from your app code.
5. In Visual Studio, open the file App.xaml.cs and add or uncomment the following `using` statement:
using Microsoft.WindowsAzure.MobileServices;
6. In this same file, uncomment the following code that defines the **MobileService** variable, and supply the URL and application key from the mobile service in the **MobileServiceClient** constructor, in that order.
//public static MobileServiceClient MobileService = new MobileServiceClient(
// "AppUrl",
// "AppKey"
//);
This creates a new instance of **MobileServiceClient** that is used to access your mobile service.
6. In the file MainPage.cs, add or uncomment the following `using` statements:
using Microsoft.WindowsAzure.MobileServices;
using Newtonsoft.Json;
7. In this DataModel folder, replace the **TodoItem** class definition with the following code:
public class TodoItem
{
public string Id { get; set; }
[JsonProperty(PropertyName = "text")]
public string Text { get; set; }
[JsonProperty(PropertyName = "complete")]
public bool Complete { get; set; }
}
7. Comment the line that defines the existing **items** collection, then uncomment the following lines:
private MobileServiceCollection items;
private IMobileServiceTable todoTable =
App.MobileService.GetTable();
This code creates a mobile services-aware binding collection (**items**) and a proxy class for the SQL Database table **TodoItem** (**todoTable**).
7. In the **InsertTodoItem** method, remove the line of code that sets the **TodoItem**.**Id** property, add the **async** modifier to the method, and uncomment the following line of code:
await todoTable.InsertAsync(todoItem);
This code inserts a new item into the table.
8. In the **RefreshTodoItems** method, add the **async** modifier to the method, then uncomment the following line of code:
items = await todoTable.ToCollectionAsync();
This sets the binding to the collection of items in the todoTable, which contains all TodoItem objects returned from the mobile service.
9. In the **UpdateCheckedTodoItem** method, add the **async** modifier to the method, and uncomment the following line of code:
await todoTable.UpdateAsync(item);
This sends an item update to the mobile service.
Now that the app has been updated to use Mobile Services for backend storage, it's time to test the app against Mobile Services.
## Test the app against your new mobile service
1. In Visual Studio, press the F5 key to run the app.
2. As before, type text in the textbox, and then click **Save**.
This sends a new item as an insert to the mobile service.
3. In the [Azure classic portal], click **Mobile Services**, and then click your mobile service.
4. Click the **Data** tab, then click **Browse**.
![][9]
Notice that the **TodoItem** table now contains data, with id values generated by Mobile Services, and that columns have been automatically added to the table to match the TodoItem class in the app.
This concludes the tutorial.
## Next steps
This tutorial demonstrated the basics of enabling a Windows Phone 8 app to work with data in Mobile Services. Next, consider reading up on one of these other topics:
* [Add authentication to your app](mobile-services-windows-phone-get-started-users.md)
Learn how to authenticate users of your app.
* [Add push notifications to your app](mobile-services-javascript-backend-windows-phone-get-started-push.md)
Learn how to send a very basic push notification to your app with Mobile Services.
* [Mobile Services C# How-to Conceptual Reference](mobile-services-dotnet-how-to-use-client-library.md)
Learn more about how to use Mobile Services with .NET.
[Download the Windows Phone 8 app project]: #download-app
[Create the mobile service]: #create-service
[Add a data table for storage]: #add-table
[Update the app to use Mobile Services]: #update-app
[Test the app against Mobile Services]: #test-app
[Next Steps]:#next-steps
[0]: ./media/mobile-services-windows-phone-get-started-data/mobile-quickstart-startup-wp8.png
[7]: ./media/mobile-services-windows-phone-get-started-data/mobile-add-nuget-package-wp.png
[8]: ./media/mobile-services-windows-phone-get-started-data/mobile-dashboard-tab.png
[9]: ./media/mobile-services-windows-phone-get-started-data/mobile-todoitem-data-browse.png
[Azure classic portal]: https://manage.windowsazure.com/
[Windows Phone 8 SDK]: http://go.microsoft.com/fwlink/p/?LinkID=268374
[Mobile Services SDK]: http://go.microsoft.com/fwlink/p/?LinkID=268375
[Developer Code Samples site]: http://go.microsoft.com/fwlink/p/?LinkId=271146
================================================
FILE: docs/mobile-services-windows-phone-get-started-users.md
================================================
# Add authentication to your Mobile Services app
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-users.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started-users.md)
- [(Windows 8.x Store C# | .NET)](mobile-services-dotnet-backend-windows-store-dotnet-get-started-users.md)
- [(Windows 8.x Store C# | Javascript)](mobile-services-windows-store-dotnet-get-started-users.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-windows-phone-get-started-users.md)
- [(Android | Javascript)](mobile-services-android-get-started-users.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started-users.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-users.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-users.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-users.md)
- [(HTML | Javascript)](mobile-services-html-get-started-users.md)
## Overview
This topic shows you how to authenticate users in Azure Mobile Services from your app. In this tutorial, you add authentication to the quickstart project using an identity provider that is supported by Mobile Services. After being successfully authenticated and authorized by Mobile Services, the user ID value is displayed.
This tutorial is also demonstrated by Nick Harris in the following video:
> [AZURE.VIDEO mobile-authorize-users-in-scripts-windows-phone]
This tutorial is based on the Mobile Services quickstart. You must also first complete the tutorial [Add Mobile Services to an existing app].
>[AZURE.NOTE]This tutorial demonstrates the authentication flow managed by Mobile Services using a variety of identity providers. This method is easy to configure and supports multiple providers. By using client-managed authentication, your app has access to additional user data maintained by the identity provider. You can get the same user data in your mobile service by by calling the **user.getIdentities()** function in server scripts. For more information, see [this post](http://go.microsoft.com/fwlink/p/?LinkId=506605).
## Register your app for authentication and configure Mobile Services
1. In the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Dashboard**, and make a note of the **Mobile Service URL** value.
2. Register your app with one or more of the following authentication providers:
* [Google](./
mobile-services-how-to-register-google-authentication.md)
* [Facebook](./
mobile-services-how-to-register-facebook-authentication.md)
* [Twitter](./
mobile-services-how-to-register-twitter-authentication.md)
* [Microsoft](./
mobile-services-how-to-register-microsoft-authentication.md)
* [Azure Active Directory](./
mobile-services-how-to-register-active-directory-authentication.md).
Make a note of the client identity and client secret values generated by the provider. Do not distribute or share the client secret.
3. Back in the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Identity** > your identity provider settings, then enter the client ID and secret value from your provider.
You've now configured both your app and your mobile service to work with your auth provider. You may optionally repeat all these steps for each additional identity provider you'd like to support.
> [AZURE.IMPORTANT] Verify that you've set the correct redirect URI on your identity provider's developer site. As described in the linked instructions for each provider above, the redirect URI may be different for a .NET backend service vs. for a JavaScript backend service. An incorrectly configured redirect URI may result in the login screen not being displayed properly and the app malfunctioning in unexpected ways.
## Restrict permissions to authenticated users
To secure your endpoints, you must restrict access to only authenticated clients.
1. In the [Azure classic portal](https://manage.windowsazure.com/), navigate to your mobile service, then click **Data** > your table name (**TodoItem**) > **Permissions**.
2. Set all of the table operation permissions to **Only authenticated users**.
This ensures that all operations against the table require an authenticated user, which is required for this tutorial. You can set different permissions on each operations to support your specific scenario.
3. In Visual Studio, open the project that you created when you completed the tutorial [Add Mobile Services to an existing app](mobile-services-windows-phone-get-started-data.md).
4. Press the F5 key to run this quickstart-based app; verify that an unhandled exception with a status code of 401 (Unauthorized) is raised after the app starts. This happens because the app attempts to access Mobile Services as an unauthenticated user, but the *TodoItem* table now requires authentication.
Next, you will update the app to authenticate users before requesting resources from the mobile service.
## Add authentication to the app
1. Open the project file mainpage.xaml.cs and add the following code snippet to the MainPage class:
private MobileServiceUser user;
private async Task Authenticate()
{
while (user == null)
{
string message;
try
{
user = await App.MobileServiceDotNetClient.LoginAsync(MobileServiceAuthenticationProvider.Twitter);
message = string.Format("You are now logged in - {0}", user.UserId);
}
catch (InvalidOperationException)
{
message = "You must log in. Login Required";
}
var dialog = new MessageDialog(message);
await dialog.ShowAsync();
}
}
This creates a member variable for storing the current user and a method to handle the authentication process. The user is authenticated by using a Twitter login.
>[AZURE.NOTE]If you are using an identity provider other than Twitter, change the value of MobileServiceAuthenticationProvider above to the value for your provider.
2. Delete or comment-out the existing **OnNavigatedTo** method override and replace it with the following method that handles the **Loaded** event for the page.
async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
await Authenticate();
RefreshTodoItems();
}
This method calls the new **Authenticate** method.
3. Replace the MainPage constructor with the following code:
// Constructor
public MainPage()
{
InitializeComponent();
this.Loaded += MainPage_Loaded;
}
This constructor also registers the handler for the Loaded event.
4. Press the F5 key to run the app and sign into the app with your chosen identity provider.
When you are successfully logged-in, the app should run without errors, and you should be able to query Mobile Services and make updates to data.
## Store the authorization tokens on the client
The previous example showed a standard sign-in, which requires the client to contact both the identity provider and the mobile service every time that the app starts. Not only is this method inefficient, you can run into usage-relates issues should many customers try to start you app at the same time. A better approach is to cache the authorization token returned by Mobile Services and try to use this first before using a provider-based sign-in.
>[AZURE.NOTE]You can cache the token issued by Mobile Services regardless of whether you are using client-managed or service-managed authentication. This tutorial uses service-managed authentication.
1. In the MainPage.xaml.cs project file, add the following **using** statements:
using System.IO.IsolatedStorage;
using System.Security.Cryptography;
2. Replace the **AuthenticateAsync** method with the following code:
private async System.Threading.Tasks.Task AuthenticateAsync()
{
string message;
// This sample uses the Facebook provider.
var provider = "Facebook";
// Provide some additional app-specific security for the encryption.
byte [] entropy = { 1, 8, 3, 6, 5 };
// Authorization credential.
MobileServiceUser user = null;
// Isolated storage for the app.
IsolatedStorageSettings settings =
IsolatedStorageSettings.ApplicationSettings;
while (user == null)
{
// Try to get an existing encrypted credential from isolated storage.
if (settings.Contains(provider))
{
// Get the encrypted byte array, decrypt and deserialize the user.
var encryptedUser = settings[provider] as byte[];
var userBytes = ProtectedData.Unprotect(encryptedUser, entropy);
user = JsonConvert.DeserializeObject(
System.Text.Encoding.Unicode.GetString(userBytes, 0, userBytes.Length));
}
if (user != null)
{
// Set the user from the stored credentials.
App.MobileService.CurrentUser = user;
try
{
// Try to return an item now to determine if the cached credential has expired.
await App.MobileService.GetTable().Take(1).ToListAsync();
}
catch (MobileServiceInvalidOperationException ex)
{
if (ex.Response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
// Remove the credential with the expired token.
settings.Remove(provider);
user = null;
continue;
}
}
}
else
{
try
{
// Login with the identity provider.
user = await App.MobileService
.LoginAsync(provider);
// Serialize the user into an array of bytes and encrypt with DPAPI.
var userBytes = System.Text.Encoding.Unicode
.GetBytes(JsonConvert.SerializeObject(user));
byte[] encryptedUser = ProtectedData.Protect(userBytes, entropy);
// Store the encrypted user credentials in local settings.
settings.Add(provider, encryptedUser);
settings.Save();
}
catch (MobileServiceInvalidOperationException ex)
{
message = "You must log in. Login Required";
}
}
message = string.Format("You are now logged in - {0}", user.UserId);
MessageBox.Show(message);
}
}
In this version of **AuthenticateAsync**, the app tries to use credentials stored encrypted in local storage to access the mobile service. A simple query is sent to verify that the stored token is not expired. When a 401 is returned, a regular provider-based sign-in is attempted. A regular sign-in is also performed when there is no stored credential.
>[AZURE.NOTE]This app tests for expired tokens during login, but token expiration can occur after authentication when the app is in use. For a solution to handling authorization errors related to expiring tokens, see the post [Caching and handling expired tokens in Azure Mobile Services managed SDK](http://blogs.msdn.com/b/carlosfigueira/archive/2014/03/13/caching-and-handling-expired-tokens-in-azure-mobile-services-managed-sdk.aspx).
3. Restart the app twice.
Notice that on the first start-up, sign-in with the provider is again required. However, on the second restart the cached credentials are used and sign-in is bypassed.
## Next steps
In the next tutorial, [Service-side authorization of Mobile Services users](mobile-services-javascript-backend-service-side-authorization.md), you will take the user ID value provided by Mobile Services based on an authenticated user and use it to filter the data returned by Mobile Services.
[Register your app for authentication and configure Mobile Services]: #register
[Restrict table permissions to authenticated users]: #permissions
[Add authentication to the app]: #add-authentication
[Next Steps]:#next-steps
[1]: ./media/mobile-services-wp8-get-started-users/mobile-services-selection.png
[2]: ./media/mobile-services-wp8-get-started-users/mobile-service-uri.png
[3]: ./media/mobile-services-wp8-get-started-users/mobile-identity-tab.png
[4]: ./media/mobile-services-wp8-get-started-users/mobile-portal-data-tables.png
[5]: ./media/mobile-services-wp8-get-started-users/mobile-portal-change-table-perms.png
[Submit an app page]: http://go.microsoft.com/fwlink/p/?LinkID=266582
[Add Mobile Services to an existing app]: mobile-services-windows-phone-get-started-data.md
[Authorize users with scripts]: mobile-services-windows-phone-authorize-users-in-scripts.md
================================================
FILE: docs/mobile-services-windows-store-dotnet-adal-sso-authentication.md
================================================
# Authenticate your app with Active Directory Authentication Library Single Sign-On
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
> [AZURE.SELECTOR-LIST (Platform | Backend)]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-adal-sso-authentication.md)
- [(Windows 8.x Store C# | .NET)](mobile-services-windows-store-dotnet-adal-sso-authentication.md)
## Overview
In this tutorial, you add authentication to the quickstart project using the Active Directory Authentication Library to support [client-directed login operations](http://msdn.microsoft.com/library/azure/jj710106.aspx) with Azure Active Directory. To support [service-directed login operations](http://msdn.microsoft.com/library/azure/dn283952.aspx) with Azure Active Directory, start with the [Add authentication to your Mobile Services app](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-users.md) tutorial.
To be able to authenticate users, you must register your application with the Azure Active Directory (AAD). This is done in two steps. First, you must register your mobile service and expose permissions on it. Second, you must register your Windows Store app and grant it access to those permissions
>[AZURE.NOTE] This tutorial is intended to help you better understand how Mobile Services enables you to do single sign-on Azure Active Directory authentication for Windows Store apps using a [client-directed login operation](http://msdn.microsoft.com/library/azure/jj710106.aspx). If this is your first experience with Mobile Services, complete the tutorial [Get started with Mobile Services].
## Prerequisites
This tutorial requires the following:
* Visual Studio 2013 running on Windows 8.1.
* Completion of the [Get started with Mobile Services] tutorial.
* Microsoft Azure Mobile Services SDK NuGet package
* Active Directory Authentication Library NuGet package
## Register your mobile service with the Azure Active Directory
In this section you will register your mobile service with the Azure Active Directory and configure permissions to allow single sign-on impersonation.
1. Register your application with your Azure Active Directory by following the [How to Register with the Azure Active Directory] topic.
2. In the [Azure classic portal](https://manage.windowsazure.com/), go back to the Azure Active Directory extension and click on your active directory
3. Click the **Applications** tab and then click your application.
4. Click **Manage Manifest**. Then click **Download Manifest** and save the application manifest to a local directory.

5. Open the application manifest file with Visual Studio. At the top of the file find the app permissions line that looks as follows:
"oauth2Permissions": [],
Replace that line with the following app permissions and save the file.
"oauth2Permissions": [
{
"adminConsentDescription": "Allow the application access to the mobile service",
"adminConsentDisplayName": "Have full access to the mobile service",
"id": "b69ee3c9-c40d-4f2a-ac80-961cd1534e40",
"isEnabled": true,
"origin": "Application",
"type": "User",
"userConsentDescription": "Allow the application full access to the mobile service on your behalf",
"userConsentDisplayName": "Have full access to the mobile service",
"value": "user_impersonation"
}
],
6. In the [Azure classic portal](https://manage.windowsazure.com/), click **Manage Manifest** for the application again and click **Upload Manifest**. Browse to the location of the application manifest that you just updated and upload the manifest.
[How to Register with the Azure Active Directory]: ./
mobile-services-how-to-register-active-directory-authentication.md
## Register your app with the Azure Active Directory
To register the app with Azure Active Directory, you must associate it to the Windows Store and have a package security identifier (SID) for the app. The package SID gets registered with the native application settings in the Azure Active Directory.
### Associate the app with a new store app name
1. In Visual Studio, right click the client app project and click **Store** and **Associate App with the Store**
![][1]
2. Sign into your Dev Center account.
3. Enter the app name you want to reserve for the app and click **Reserve**.
![][2]
4. Select the new app name and click **Next**.
5. Click **Associate** to associate the app with the store name.
### Retrieve the package SID for your app.
Now you need to retrieve your package SID which will be configured with the native app settings.
1. Log into your [Windows Dev Center Dashboard] and click **Edit** on the app.
![][3]
2. Then click **App management** > **App identity** and Copy your package SID from the page.
![][4]
### Create the native app registration
1. Navigate to **Active Directory** in the [classic portal], then click your directory.
![][7]
2. Click the **Applications** tab at the top, then click to **ADD** an app.
![][8]
3. Click **Add an application my organization is developing**.
4. In the Add Application Wizard, enter a **Name** for your application and click the **Native Client Application** type. Then click to continue.
![][9]
5. In the **Redirect URI** box, paste the App package SID you copied earlier then click to complete the native app registration.
![][10]
6. Click the **Configure** tab for the native application and copy the **Client ID**. You will need this later.
![][11]
7. Scroll the page down to the **permissions to other applications** section and grant full access to the mobile service application that you registered earlier. Then click **Save**
![][12]
Your mobile service is now configured in AAD to receive single sign-on logins from your app.
## Configure the mobile service to require authentication
By default, all requests to mobile service resources are restricted to clients that present the application key, which does not strictly secure access to resources. To secure your resources, you must restrict access to only authenticated clients.
1. In Visual Studio, open your mobile service project, expand the Controllers folder, and open **TodoItemController.cs**. The **TodoItemController** class implements data access for the TodoItem table. Add the following `using` statement:
using Microsoft.WindowsAzure.Mobile.Service.Security;
2. Apply the following _AuthorizeLevel_ attribute to the **TodoItemController** class.
[AuthorizeLevel(AuthorizationLevel.User)]
This makes sure that all operations against the _TodoItem_ table require an authenticated user. You can also apply the *AuthorizeLevel* attribute at the method level.
3. (Optional) If you wish to debug authentication locally, expand the `App_Start` folder, open **WebApiConfig.cs**, and add the following code to the **Register** method.
config.SetIsHosted(true);
This tells the local mobile service project to run as if it is being hosted in Azure, including honoring the *AuthorizeLevel* settings. Without this setting, all HTTP requests to localhost are permitted without authentication despite the *AuthorizeLevel* setting. When you enable self-hosted mode, you also need to set a value for the local application key.
4. (Optional) In the web.config project file, set a string value for the `MS_ApplicationKey` app setting.
This is the password that you use (with no username) to test the API help pages when you run the service locally. This string value is not used by the live site in Azure, and you do not need to use the actual application key; any valid string value will work.
4. Republish your project.
## Add authentication code to the client app
1. Open your Windows store client app project in Visual Studio.
1. In the Solution Explorer window of Visual Studio, right click the project and click **Manage NuGet Packages**.
2. In the NuGet Package manager, click **Online**. Enter **Microsoft.IdentityModel.Clients.ActiveDirectory** as a search term. Then click **Install** to install the Active Directory Authentication Library Nuget package.

4. In the Solution Explorer window of Visual Studio, open the MainPage.cs file and add the following using statements.
using Windows.UI.Popups;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Newtonsoft.Json.Linq;
5. Add the following code to the MainPage class which declares the `AuthenticateAsync` method.
private MobileServiceUser user;
private async Task AuthenticateAsync()
{
string authority = "";
string resourceURI = "";
string clientID = "";
while (user == null)
{
string message;
try
{
AuthenticationContext ac = new AuthenticationContext(authority);
AuthenticationResult ar = await ac.AcquireTokenAsync(resourceURI, clientID, (Uri) null);
JObject payload = new JObject();
payload["access_token"] = ar.AccessToken;
user = await App.MobileService.LoginAsync(MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory, payload);
message = string.Format("You are now logged in - {0}", user.UserId);
}
catch (InvalidOperationException)
{
message = "You must log in. Login Required";
}
var dialog = new MessageDialog(message);
dialog.Commands.Add(new UICommand("OK"));
await dialog.ShowAsync();
}
}
6. In the code for the `AuthenticateAsync` method above, replace **INSERT-AUTHORITY-HERE** with the name of the tenant in which you provisioned your application, the format should be https://login.windows.net/tenant-name.onmicrosoft.com. This value can be copied out of the Domain tab in your Azure Active Directory in the [Azure classic portal].
7. In the code for the `AuthenticateAsync` method above, replace **INSERT-RESOURCE-URI-HERE** with the **App ID URI** for your mobile service. If you followed the [How to Register with the Azure Active Directory] topic your App ID URI should be similar to https://todolist.azure-mobile.net/login/aad.
8. In the code for the `AuthenticateAsync` method above, replace **INSERT-CLIENT-ID-HERE** with the client ID you copied from the native client application.
9. In the Solution Explorer window for Visual Studio, open the Package.appxmanifest file in the client project. Click the **Capabilities** tab and enable **Enterprise Application** and **Private Networks (Client & Server)**. Save the file.
![][14]
10. In the MainPage.cs file, update the `OnNavigatedTo` event handler to call the `AuthenticateAsync` method as follows.
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
await AuthenticateAsync();
await RefreshTodoItems();
}
## Test the client using authentication
1. In Visual Studio,run the client app.
2. You will receive a prompt to login against your Azure Active Directory.
3. The app authenticates and returns the todo items.
![][15]
[0]: ./media/mobile-services-windows-store-dotnet-adal-sso-authenticate/mobile-services-aad-app-manage-manifest.png
[1]: ./media/mobile-services-windows-store-dotnet-adal-sso-authentication/mobile-services-vs-associate-app.png
[2]: ./media/mobile-services-windows-store-dotnet-adal-sso-authentication/mobile-services-vs-reserve-store-appname.png
[3]: ./media/mobile-services-windows-store-dotnet-adal-sso-authentication/mobile-services-store-app-edit.png
[4]: ./media/mobile-services-windows-store-dotnet-adal-sso-authentication/mobile-services-store-app-services.png
[5]: ./media/mobile-services-windows-store-dotnet-adal-sso-authentication/mobile-services-live-services-site.png
[6]: ./media/mobile-services-windows-store-dotnet-adal-sso-authentication/mobile-services-store-app-package-sid.png
[7]: ./media/mobile-services-windows-store-dotnet-adal-sso-authentication/mobile-services-select-aad.png
[8]: ./media/mobile-services-windows-store-dotnet-adal-sso-authentication/mobile-services-aad-applications-tab.png
[9]: ./media/mobile-services-windows-store-dotnet-adal-sso-authentication/mobile-services-native-selection.png
[10]: ./media/mobile-services-windows-store-dotnet-adal-sso-authentication/mobile-services-native-sid-redirect-uri.png
[11]: ./media/mobile-services-windows-store-dotnet-adal-sso-authentication/mobile-services-native-client-id.png
[12]: ./media/mobile-services-windows-store-dotnet-adal-sso-authentication/mobile-services-native-add-permissions.png
[14]: ./media/mobile-services-windows-store-dotnet-adal-sso-authentication/mobile-services-package-appxmanifest.png
[15]: ./media/mobile-services-windows-store-dotnet-adal-sso-authentication/mobile-services-app-run.png
[How to Register with the Azure Active Directory]: mobile-services-how-to-register-active-directory-authentication.md
[Azure classic portal]: https://manage.windowsazure.com/
[classic portal]: https://manage.windowsazure.com/
[Get started with Mobile Services]: mobile-services-dotnet-backend-windows-store-dotnet-get-started.md
[Windows Dev Center Dashboard]: http://go.microsoft.com/fwlink/p/?LinkID=266734
================================================
FILE: docs/mobile-services-windows-store-dotnet-get-started-offline-data.md
================================================
# Using offline data sync in Mobile Services
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
> [AZURE.SELECTOR]
- [Android)](mobile-services-android-get-started-offline-data.md)
- [iOS](mobile-services-ios-get-started-offline-data.md)
- [Windows](mobile-services-windows-store-dotnet-get-started-offline-data.md)
- [Xamarin.Android](mobile-services-xamarin-android-get-started-offline-data.md)
- [Xamarin.iOS](mobile-services-xamarin-ios-get-started-offline-data.md)
This tutorial shows you how to add offline support to a Windows Universal Store app using Azure Mobile Services. Offline support will allow you to interact with a local database when your app is in an offline scenario. Once your app is online with the backend database, you sync your local changes using the offline features.
If you prefer to watch a video, the clip to the right follows the same steps as this tutorial.
> [AZURE.VIDEO build-offline-apps-with-mobile-services]
In this tutorial, you update the Universal app project from the [Get started with Mobile Services] tutorial to support the offline features of Azure Mobile Services. Then you will add data in a disconnected offline scenario, sync those items to the online database, and then log in to the [Azure classic portal] to view changes to data made when running the app.
>[AZURE.NOTE] This tutorial is intended to help you better understand how Mobile Services enables you to use Azure to store and retrieve data in a Windows Store app. If this is your first experience with Mobile Services, you should complete the tutorial [Get started with Mobile Services] first.
## Prerequisites
This tutorial requires the following:
* Visual Studio 2013 running on Windows 8.1.
* Completion of the [Get started with Mobile Services].
* [Azure Mobile Services SDK version 1.3.0 (or later)][Mobile Services SDK Nuget]
* [Azure Mobile Services SQLite Store version 1.0.0 (or later)][SQLite store nuget]
* [SQLite for Windows 8.1](http://www.sqlite.org/download.html)
* An Azure account. If you don't have an account, you can sign up for an Azure trial and get up to 10 free mobile services that you can keep using even after your trial ends. For details, see [Azure Free Trial](https://azure.microsoft.com/pricing/free-trial/?WT.mc_id=AE564AB28).
## Update the app to support offline features
Azure Mobile Services offline features allow you to interact with a local database when you are in an offline scenario with your Mobile Service. To use these features in your app, you initialize a `MobileServiceClient.SyncContext` to a local store. Then reference your table through the `IMobileServiceSyncTable` interface. In this tutorial we use SQLite for the local store.
>[AZURE.NOTE] You can skip this section and just get the example project that already has offline support from the GitHub samples repository for Mobile Services. The sample project with offline support enabled is located here, [TodoList Offline Sample].
1. Install the SQLite runtime for Windows 8.1 and Windows Phone 8.1.
* **Windows 8.1 Runtime:** Install [SQLite for Windows 8.1].
* **Windows Phone 8.1:** Install [SQLite for Windows Phone 8.1].
>[AZURE.NOTE] If you are using Internet Explorer, clicking the link to install SQLite may prompt you to download the .vsix as a .zip file. Save the file to a location on your hard drive with the .vsix extension instead of .zip. The double click the .vsix file in Windows Explorer to run the installation.
2. In Visual Studio open the project that you completed in the [Get started with Mobile Services] tutorial. Install the **WindowsAzure.MobileServices.SQLiteStore** NuGet package for the Windows 8.1 runtime and Windows Phone 8.1 projects.
* **Windows 8.1:** In Solution Explorer, right click the Windows 8.1 project and click **Manage Nuget Packages** to run NuGet Package Manager. Search for **SQLiteStore** to install the `WindowsAzure.MobileServices.SQLiteStore` package.
* **Windows Phone 8.1:** Right click the Windows Phone 8.1 project and click **Manage Nuget Packages** to run NuGet Package Manager. Search for **SQLiteStore** to install the `WindowsAzure.MobileServices.SQLiteStore` package.
>[AZURE.NOTE] If the installation creates a reference to an older version of SQLite, you can just delete that duplicate reference.
![][2]
2. In Solution Explorer, right click **References** for the Windows 8.1 Runtime and Windows Phone 8.1 platform projects and ensure there is a reference to SQLite, which is located in the **Extensions** section.
![][1]
**Windows 8.1 Runtime**
![][11]
**Windows Phone 8.1**
3. The SQLite Runtime requires you to change the processor architecture of the project being built to **x86**, **x64**, or **ARM**. **Any CPU** is not supported. In Solution Explorer, click the Solution at the top, then change the processor architecture drop down box to one of the supported settings that you want to test.
![][13]
5. In Solution Explorer, in the shared project, open the MainPage.cs file. Uncomment the following using statements at the top of the file:
using Microsoft.WindowsAzure.MobileServices.SQLiteStore; // offline sync
using Microsoft.WindowsAzure.MobileServices.Sync; // offline sync
6. In MainPage.cs, comment the definition of `todoTable` and uncomment the one on the following line that calls `MobileServicesClient.GetSyncTable()`:
//private IMobileServiceTable todoTable = App.MobileService.GetTable();
private IMobileServiceSyncTable todoTable = App.MobileService.GetSyncTable(); // offline sync
7. In MainPage.cs, in the region marked `Offline sync`, uncomment the methods `InitLocalStoreAsync` and `SyncAsync`. The method `InitLocalStoreAsync` initializes the client sync context with a SQLite store.
private async Task InitLocalStoreAsync()
{
if (!App.MobileService.SyncContext.IsInitialized)
{
var store = new MobileServiceSQLiteStore("localstore.db");
store.DefineTable();
await App.MobileService.SyncContext.InitializeAsync(store);
}
await SyncAsync();
}
private async Task SyncAsync()
{
await App.MobileService.SyncContext.PushAsync();
await todoTable.PullAsync("todoItems", todoTable.CreateQuery());
}
8. In the `OnNavigatedTo` event handler, uncomment the call to `InitLocalStoreAsync`:
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
await InitLocalStoreAsync(); // offline sync
await RefreshTodoItems();
}
9. Uncommment the 3 calls to `SyncAsync` in the methods `InsertTodoItem`, `UpdateCheckedTodoItem`, and `ButtonRefresh_Click`:
private async Task InsertTodoItem(TodoItem todoItem)
{
await todoTable.InsertAsync(todoItem);
items.Add(todoItem);
await SyncAsync(); // offline sync
}
private async Task UpdateCheckedTodoItem(TodoItem item)
{
await todoTable.UpdateAsync(item);
items.Remove(item);
ListItems.Focus(Windows.UI.Xaml.FocusState.Unfocused);
await SyncAsync(); // offline sync
}
private async void ButtonRefresh_Click(object sender, RoutedEventArgs e)
{
ButtonRefresh.IsEnabled = false;
await SyncAsync(); // offline sync
await RefreshTodoItems();
ButtonRefresh.IsEnabled = true;
}
10. Add exception handlers in the `SyncAsync` method:
private async Task SyncAsync()
{
String errorString = null;
try
{
await App.MobileService.SyncContext.PushAsync();
await todoTable.PullAsync("todoItems", todoTable.CreateQuery()); // first param is query ID, used for incremental sync
}
catch (MobileServicePushFailedException ex)
{
errorString = "Push failed because of sync errors: " +
ex.PushResult.Errors.Count + " errors, message: " + ex.Message;
}
catch (Exception ex)
{
errorString = "Pull failed: " + ex.Message +
"\n\nIf you are still in an offline scenario, " +
"you can try your Pull again when connected with your Mobile Serice.";
}
if (errorString != null)
{
MessageDialog d = new MessageDialog(errorString);
await d.ShowAsync();
}
}
In this example, we retrieve all records in the remote `todoTable`, but it is also possible to filter records by passing a query. The first parameter to `PullAsync` is a query ID that is used for incremental sync, which uses the `UpdatedAt` timestamp to get only records modified since the last sync. The query ID should be a descriptive string that is unique for each logical query in your app. To opt-out of incremental sync, pass `null` as the query ID. This will retrieve all records on each pull operation, which is potentially inefficient.
>[AZURE.NOTE] * To remove records from the device local store when they have been deleted in your mobile service database, you should enable [Soft Delete]. Otherwise, your app should periodically call `IMobileServiceSyncTable.PurgeAsync()` to purge the local store.
Note that the `MobileServicePushFailedException` can occur for both a push and a pull operation. It can occur for a pull because the pull operation internally executes a push to make sure all tables along with any relationships are consistent. The next tutorial, [Handling conflicts with offline support for Mobile Services], shows how to handle these sync related exceptions.
11. In Visual Studio, press the **F5** key to rebuild and run the app. The app will behave the same as it did before the offline sync changes, because it does a sync operation on the insert, update, and refresh operations.
## Update the sync behavior of the app
In this section, you will modify the app so that it does not sync on the insert and update operations, but only when the **Refresh** button is pressed. Then, you will break the app connection with the mobile service to simulate an offline scenario. When you add data items, they will be held in the local store, but not synced to the mobile service.
1. Open MainPage.cs in the shared project. Edit the methods `InsertTodoItem` and `UpdateCheckedTodoItem` to comment out the calls to `SyncAsync`.
2. Edit App.xaml.cs in the shared project. Comment out the initialization of the **MobileServiceClient** and add the following lines, which use an invalid mobile service URL:
public static MobileServiceClient MobileService = new MobileServiceClient(
"https://your-mobile-service.azure-mobile.xxx/",
"AppKey"
);
3. In `InitLocalStoreAsync()`, comment out the call to `SyncAsync()`, so that the app does not perform a sync on launch.
4. Press **F5** to build and run the app. Enter some new todo items and click **Save** for each one. The new todo items exist only in the local store until they can be pushed to the mobile service. The client app behaves as if its connected to the mobile service supporting all create, read, update, delete (CRUD) operations.
5. Close the app and restart it to verify that the new items you created are persisted to the local store.
## Update the app to reconnect your mobile service
In this section you reconnect the app to the mobile service. This simulates the app moving from an offline state to an online state with the mobile service. When you press the Refresh button, data will be synced to your mobile service.
1. Open App.xaml.cs in the shared project. Uncomment your previous initialization of `MobileServiceClient` to add back the correct mobile service URL and app key.
2. Press the **F5** key to rebuild and run the app. Notice that the data looks the same as the offline scenario even though the app is now connected to the mobile service. This is because this app always works with the `IMobileServiceSyncTable` that is pointed to the local store.
3. Log into the [Azure classic portal] and look at the database for your mobile service. If your service uses the JavaScript backend for mobile services, you can browse the data from the **Data** tab of the mobile service.
If you are using the .NET backend for your mobile service, in Visual Studio go to **Server Explorer** -> **Azure** -> **SQL Databases**. Right click your database and select **Open in SQL Server Object Explorer**.
Notice the data has not been synchronized between the database and the local store.
![][6]
4. In the app, press the **Refresh** button. This causes the app to call `PushAsync` and `PullAsync`. This push operation sends the local store items to the mobile service, then retrieves new data from the mobile service.
A push operation is executed off the `MobileServiceClient.SyncContext` instead of the `IMobileServicesSyncTable` and pushes changes on all tables associated with that sync context. This is to cover scenarios where there are relationships between tables.
![][7]
5. In the app, click the check box beside a few items to complete them in the local store.
![][8]
6. Push the **Refresh** button again, which causes `SyncAsync` to be called. `SyncAsync` calls both push and pull, but in this case we could have removed the call to `PushAsync`. This is because a **pull always does a push first**. This is to ensure all tables in the local store along with relationships remain consistent.
![][10]
## Summary
In order to support the offline features of mobile services, we used the `IMobileServiceSyncTable` interface and initialized `MobileServiceClient.SyncContext` with a local store. In this case the local store was a SQLite database.
The normal CRUD operations for mobile services work as if the app is still connected but, all the operations occur against the local store.
When we wanted to synchronize the local store with the server, we used the `IMobileServiceSyncTable.PullAsync` and `MobileServiceClient.SyncContext.PushAsync` methods.
* To push changes to the server, we called `IMobileServiceSyncContext.PushAsync()`. This method is a member of `IMobileServicesSyncContext` instead of the sync table because it will push changes across all tables.
Only records that have been modified in some way locally (through CUD operations) will be sent to the server.
* To pull data from a table on the server to the app, we called `IMobileServiceSyncTable.PullAsync`.
A pull always issues a push first. This is to ensure all tables in the local store along with relationships remain consistent.
There are also overloads of `PullAsync()` that allow a query to be specified in order to filter the data that is stored on the client. If a query is not passed, `PullAsync()` will pull all rows in the corresponding table (or query). You can pass the query to filter only the changes your app needs to sync with.
* To enable incremental sync, pass a query ID to `PullAsync()`. The query ID is used to store the last updated timestamp from the results of the last pull operation. The query ID should be a descriptive string that is unique for each logical query in your app. If the query has a parameter, then the same parameter value has to be part of the query ID.
For instance, if you are filtering on userid, it needs to be part of the query ID:
await PullAsync("todoItems" + userid, syncTable.Where(u => u.UserId = userid));
If you want to opt out of incremental sync, pass `null` as the query ID. In this case, all records will be retrieved on every call to `PullAsync`, which is potentially inefficient.
* To remove records from the device local store when they have been deleted in your mobile service database, you should enable [Soft Delete]. Otherwise, your app should periodically call `IMobileServiceSyncTable.PurgeAsync()` to purge the local store.
## Next steps
* [Handling conflicts with offline support for Mobile Services]
* [Using Soft Delete in Mobile Services][Soft Delete]
[Update the app to support offline features]: #enable-offline-app
[Update the sync behavior of the app]: #update-sync
[Update the app to reconnect your mobile service]: #update-online-app
[Next Steps]:#next-steps
[1]: ./media/mobile-services-windows-store-dotnet-get-started-offline-data/mobile-services-add-reference-sqlite-dialog.png
[2]: ./media/mobile-services-windows-store-dotnet-get-started-offline-data/mobile-services-sqlitestore-nuget.png
[6]: ./media/mobile-services-windows-store-dotnet-get-started-offline-data/mobile-data-browse.png
[7]: ./media/mobile-services-windows-store-dotnet-get-started-offline-data/mobile-data-browse2.png
[8]: ./media/mobile-services-windows-store-dotnet-get-started-offline-data/mobile-services-online-app-run2.png
[10]: ./media/mobile-services-windows-store-dotnet-get-started-offline-data/mobile-data-browse3.png
[11]: ./media/mobile-services-windows-store-dotnet-get-started-offline-data/mobile-services-add-wp81-reference-sqlite-dialog.png
[12]: ./media/mobile-services-windows-store-dotnet-get-started-offline-data/new-synchandler-class.png
[13]: ./media/mobile-services-windows-store-dotnet-get-started-offline-data/cpu-architecture.png
[Handling conflicts with offline support for Mobile Services]: mobile-services-windows-store-dotnet-handling-conflicts-offline-data.md
[TodoList Offline Sample]: http://go.microsoft.com/fwlink/?LinkId=394777
[Get started with Mobile Services]: https://azure.microsoft.com/develop/mobile/tutorials/get-started/#create-new-service
[Getting Started]: mobile-services-dotnet-backend-windows-phone-get-started.md
[Get started with Mobile Services]: mobile-services-windows-store-get-started.md
[SQLite for Windows 8.1]: http://go.microsoft.com/fwlink/?LinkId=394776
[SQLite for Windows Phone 8.1]: http://go.microsoft.com/fwlink/?LinkId=397953
[Soft Delete]: mobile-services-using-soft-delete.md
[Mobile Services SDK Nuget]: http://www.nuget.org/packages/WindowsAzure.MobileServices/1.3.0
[SQLite store nuget]: http://www.nuget.org/packages/WindowsAzure.MobileServices.SQLiteStore/1.0.0
[Azure classic portal]: https://manage.windowsazure.com
================================================
FILE: docs/mobile-services-windows-store-dotnet-handle-database-conflicts.md
================================================
# Handling database write conflicts
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
## Overview
This tutorial is intended to help you better understand how to handle conflicts that occur when two or more clients write to the same database record in a Windows Store app. Two or more clients may write changes to the same item, at the same time, in some scenarios. Without any conflict detection, the last write would overwrite any previous updates even if this was not the desired result. Azure Mobile Services provides support for detecting and resolving these conflicts. This topic walks you through the steps that allow you to handle database write conflicts on both the server and in your application.
In this tutorial you will add functionality to the quickstart app to handle contentions that can occur when updating the TodoItem database.
## Prerequisites
This tutorial requires the following
+ Microsoft Visual Studio 2013 or later.
+ This tutorial is based on the Mobile Services quickstart. Before you start this tutorial, you must first complete [Get started with Mobile Services].
+ [Azure Account]
+ Azure Mobile Services NuGet Package 1.1.0 or later. To get the latest version, follow these steps below:
1. In Visual Studio, open the project and right-click the project in Solution Explorer then click **Manage Nuget Packages**.
![][19]
2. Expand **Online** and click **Microsoft and .NET**. In the search text box enter **Azure Mobile Services**. Click **Install** on the **Azure Mobile Services** NuGet Package.
![][20]
## Update the application to allow updates
In this section you will update the TodoList user interface to allow updating the text of each item in a ListBox control. The ListBox will contain a CheckBox and TextBox control for each item in the database table. You will be able to update the text field of the TodoItem. The application will handle the `LostFocus` event from that TextBox to update the item in the database.
1. In Visual Studio, open the TodoList project you downloaded in the [Get started with Mobile Services] tutorial.
2. In the Visual Studio Solution Explorer, open MainPage.xaml and replace the `ListView` definition with the `ListView` shown below and save the change.
4. In the Visual Studio Solution Explorer, open MainPage.cs in the shared project. Add the event handler to the MainPage for the TextBox `LostFocus` event as shown below.
private async void ToDoText_LostFocus(object sender, RoutedEventArgs e)
{
TextBox tb = (TextBox)sender;
TodoItem item = tb.DataContext as TodoItem;
//let's see if the text changed
if (item.Text != tb.Text)
{
item.Text = tb.Text;
await UpdateToDoItem(item);
}
}
4. In MainPage.cs for the shared project, add the definition for the MainPage `UpdateToDoItem()` method referenced in the event handler as shown below.
private async Task UpdateToDoItem(TodoItem item)
{
Exception exception = null;
try
{
//update at the remote table
await todoTable.UpdateAsync(item);
}
catch (Exception ex)
{
exception = ex;
}
if (exception != null)
{
await new MessageDialog(exception.Message, "Update Failed").ShowAsync();
}
}
The application now writes the text changes to each item back to the database when the TextBox loses focus.
## Enable Conflict Detection in your application
Two or more clients may write changes to the same item, at the same time, in some scenarios. Without any conflict detection, the last write would overwrite any previous updates even if this was not the desired result. [Optimistic Concurrency Control] assumes that each transaction can commit and therefore does not use any resource locking. Before committing a transaction, optimistic concurrency control verifies that no other transaction has modified the data. If the data has been modified, the committing transaction is rolled back. Azure Mobile Services supports optimistic concurrency control by tracking changes to each item using the `__version` system property column that is added to each table. In this section, we will enable the application to detect these write conflicts through the `__version` system property. The application will be notified by a `MobileServicePreconditionFailedException` during an update attempt if the record has changed since the last query. It will then be able to make a choice of whether to commit its change to the database or leave the last change to the database intact. For more information on the System Properties for Mobile Services, see [System Properties].
1. Open TodoItem.cs in the shared project and update the `TodoItem` class definition with the following code to include the `__version` system property enabling support for write conflict detection.
public class TodoItem
{
public string Id { get; set; }
[JsonProperty(PropertyName = "text")]
public string Text { get; set; }
[JsonProperty(PropertyName = "complete")]
public bool Complete { get; set; }
[JsonProperty(PropertyName = "__version")]
public string Version { set; get; }
}
> [AZURE.NOTE] When using untyped tables, enable optimistic concurrency by adding the Version flag to the SystemProperties of the table.
>
>`````
>//Enable optimistic concurrency by retrieving __version
>todoTable.SystemProperties |= MobileServiceSystemProperties.Version;
>`````
2. By adding the `Version` property to the `TodoItem` class, the application will be notified with a `MobileServicePreconditionFailedException` exception during an update if the record has changed since the last query. This exception includes the latest version of the item from the server. In MainPage.cs for the shared project, add the following code to handle the exception in the `UpdateToDoItem()` method.
private async Task UpdateToDoItem(TodoItem item)
{
Exception exception = null;
try
{
//update at the remote table
await todoTable.UpdateAsync(item);
}
catch (MobileServicePreconditionFailedException writeException)
{
exception = writeException;
}
catch (Exception ex)
{
exception = ex;
}
if (exception != null)
{
if (exception is MobileServicePreconditionFailedException)
{
//Conflict detected, the item has changed since the last query
//Resolve the conflict between the local and server item
await ResolveConflict(item, ((MobileServicePreconditionFailedException) exception).Item);
}
else
{
await new MessageDialog(exception.Message, "Update Failed").ShowAsync();
}
}
}
3. In MainPage.cs, add the definition for the `ResolveConflict()` method referenced in `UpdateToDoItem()`. Notice that in order to resolve the conflict, you set the local item's version to the updated version from the server before committing the user's decision. Otherwise, you will continually encounter the conflict.
private async Task ResolveConflict(TodoItem localItem, TodoItem serverItem)
{
//Ask user to choose the resolution between versions
MessageDialog msgDialog = new MessageDialog(String.Format("Server Text: \"{0}\" \nLocal Text: \"{1}\"\n",
serverItem.Text, localItem.Text),
"CONFLICT DETECTED - Select a resolution:");
UICommand localBtn = new UICommand("Commit Local Text");
UICommand ServerBtn = new UICommand("Leave Server Text");
msgDialog.Commands.Add(localBtn);
msgDialog.Commands.Add(ServerBtn);
localBtn.Invoked = async (IUICommand command) =>
{
// To resolve the conflict, update the version of the
// item being committed. Otherwise, you will keep
// catching a MobileServicePreConditionFailedException.
localItem.Version = serverItem.Version;
// Updating recursively here just in case another
// change happened while the user was making a decision
await UpdateToDoItem(localItem);
};
ServerBtn.Invoked = async (IUICommand command) =>
{
RefreshTodoItems();
};
await msgDialog.ShowAsync();
}
## Test database write conflicts in the application
In this section you will build a Windows Store app package to install the app on a second machine or virtual machine. Then you will run the app on both machines generating a write conflict to test the code. Both instances of the app will attempt to update the same item's `text` property requiring the user to resolve the conflict.
1. Create a Windows Store app package to install on second machine or virtual machine. To do this, click **Project**->**Store**->**Create App Packages** in Visual Studio.
![][0]
2. On the Create Your Packages screen, click **No** as this package will not be uploaded to the Windows Store. Then click **Next**.
![][1]
3. On the Select and Configure Packages screen, accept the defaults and click **Create**.
![][10]
4. On the Package Creation Completed screen, click the **Output location** link to open the package location.
![][11]
5. Copy the package folder, "todolist_1.0.0.0_AnyCPU_Debug_Test", to the second machine. On that machine, open the package folder and right click on the **Add-AppDevPackage.ps1** PowerShell script and click **Run with PowerShell** as shown below. Follow the prompts to install the app.
![][12]
5. Run instance 1 of the app in Visual Studio by clicking **Debug**->**Start Debugging**. On the Start screen of the second machine, click the down arrow to see "Apps by name". Then click the **todolist** app to run instance 2 of the app.
App Instance 1
![][2]
App Instance 2
![][2]
6. In instance 1 of the app, update the text of the last item to **Test Write 1**, then click another text box so that the `LostFocus` event handler updates the database. The screenshot below shows an example.
App Instance 1
![][3]
App Instance 2
![][2]
7. At this point the corresponding item in instance 2 of the app has an old version of the item. In that instance of the app, enter **Test Write 2** for the `text` property. Then click another text box so the `LostFocus` event handler attempts to update the database with the old `_version` property.
App Instance 1
![][4]
App Instance 2
![][5]
8. Since the `__version` value used with the update attempt didn't match the server `__version` value, the Mobile Services SDK throws a `MobileServicePreconditionFailedException` allowing the app to resolve this conflict. To resolve the conflict, you can click **Commit Local Text** to commit the values from instance 2. Alternatively, click **Leave Server Text** to discard the values in instance 2, leaving the values from instance 1 of the app committed.
App Instance 1
![][4]
App Instance 2
![][6]
## Automatically handling conflict resolution in server scripts
You can detect and resolve write conflicts in server scripts. This is a good idea when you can use scripted logic instead of user interaction to resolve the conflict. In this section, you will add a server side script to the TodoItem table for the application. The logic this script will use to resolve conflicts is as follows:
+ If the TodoItem's ` complete` field is set to true, then it is considered completed and `text` can no longer be changed.
+ If the TodoItem's ` complete` field is still false, then attempts to update `text` will be comitted.
The following steps walk you through adding the server update script and testing it.
1. Log into the [Azure classic portal], click **Mobile Services**, and then click your app.
![][7]
2. Click the **Data** tab, then click the **TodoItem** table.
![][8]
3. Click **Script**, then select the **Update** operation.
![][9]
4. Replace the existing script with the following function, and then click **Save**.
function update(item, user, request) {
request.execute({
conflict: function (serverRecord) {
// Only committing changes if the item is not completed.
if (serverRecord.complete === false) {
//write the updated item to the table
request.execute();
}
else
{
request.respond(statusCodes.FORBIDDEN, 'The item is already completed.');
}
}
});
}
5. Run the **todolist** app on both machines. Change the TodoItem `text` for the last item in instance 2. Then click another text box so the `LostFocus` event handler updates the database.
App Instance 1
![][4]
App Instance 2
![][5]
6. In instance 1 of the app, enter a different value for the last text property. Then click another text box so the `LostFocus` event handler attempts to update the database with an incorrect `__version` property.
App Instance 1
![][13]
App Instance 2
![][14]
7. Notice that no exception was encountered in the app since the server script resolved the conflict allowing the update since the item is not marked complete. To see that the update was truly successful, click **Refresh** in instance 2 to re-query the database.
App Instance 1
![][15]
App Instance 2
![][15]
8. In instance 1, click the check box to complete the last Todo item.
App Instance 1
![][16]
App Instance 2
![][15]
9. In instance 2, try to update the last TodoItem's text and trigger the `LostFocus` event. In response to the conflict, the script resolved it by refusing the update because the item was already completed.
App Instance 1
![][17]
App Instance 2
![][18]
## Next steps
This tutorial demonstrated how to enable a Windows Store app to handle write conflicts when working with data in Mobile Services. Next, consider completing one of the following Windows Store tutorials:
* [Add authentication to your app]
Learn how to authenticate users of your app.
* [Add push notifications to your app]
Learn how to send a very basic push notification to your app with Mobile Services.
[0]: ./media/mobile-services-windows-store-dotnet-handle-database-conflicts/Mobile-oc-store-create-app-package1.png
[1]: ./media/mobile-services-windows-store-dotnet-handle-database-conflicts/Mobile-oc-store-create-app-package2.png
[2]: ./media/mobile-services-windows-store-dotnet-handle-database-conflicts/Mobile-oc-store-app1.png
[3]: ./media/mobile-services-windows-store-dotnet-handle-database-conflicts/Mobile-oc-store-app1-write1.png
[4]: ./media/mobile-services-windows-store-dotnet-handle-database-conflicts/Mobile-oc-store-app1-write2.png
[5]: ./media/mobile-services-windows-store-dotnet-handle-database-conflicts/Mobile-oc-store-app2-write2.png
[6]: ./media/mobile-services-windows-store-dotnet-handle-database-conflicts/Mobile-oc-store-app2-write2-conflict.png
[7]: ./media/mobile-services-windows-store-dotnet-handle-database-conflicts/mobile-services-selection.png
[8]: ./media/mobile-services-windows-store-dotnet-handle-database-conflicts/mobile-portal-data-tables.png
[9]: ./media/mobile-services-windows-store-dotnet-handle-database-conflicts/mobile-insert-script-users.png
[10]: ./media/mobile-services-windows-store-dotnet-handle-database-conflicts/Mobile-oc-store-create-app-package3.png
[11]: ./media/mobile-services-windows-store-dotnet-handle-database-conflicts/Mobile-oc-store-create-app-package4.png
[12]: ./media/mobile-services-windows-store-dotnet-handle-database-conflicts/Mobile-oc-store-install-app-package.png
[13]: ./media/mobile-services-windows-store-dotnet-handle-database-conflicts/Mobile-oc-store-app1-write3.png
[14]: ./media/mobile-services-windows-store-dotnet-handle-database-conflicts/Mobile-oc-store-app2-write3.png
[15]: ./media/mobile-services-windows-store-dotnet-handle-database-conflicts/Mobile-oc-store-write3.png
[16]: ./media/mobile-services-windows-store-dotnet-handle-database-conflicts/Mobile-oc-store-checkbox.png
[17]: ./media/mobile-services-windows-store-dotnet-handle-database-conflicts/Mobile-oc-store-2-items.png
[18]: ./media/mobile-services-windows-store-dotnet-handle-database-conflicts/Mobile-oc-store-already-complete.png
[19]: ./media/mobile-services-windows-store-dotnet-handle-database-conflicts/mobile-manage-nuget-packages-VS.png
[20]: ./media/mobile-services-windows-store-dotnet-handle-database-conflicts/mobile-manage-nuget-packages-dialog.png
[Optimistic Concurrency Control]: http://go.microsoft.com/fwlink/?LinkId=330935
[Get started with Mobile Services]: https://azure.microsoft.com/develop/mobile/tutorials/get-started/#create-new-service
[Azure Account]: http://www.windowsazure.com/pricing/free-trial/
[Validate and modify data with scripts]: https://azure.microsoft.com/develop/mobile/tutorials/validate-modify-and-augment-data-dotnet
[Refine queries with paging]: https://azure.microsoft.com/develop/mobile/tutorials/add-paging-to-data-dotnet
[Get started with Mobile Services]: https://azure.microsoft.com/develop/mobile/tutorials/get-started
[Get started with data]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-data-dotnet
[Add authentication to your app]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-users-dotnet
[Add push notifications to your app]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-push-dotnet
[Azure classic portal]: https://manage.windowsazure.com/
[Windows Phone 8 SDK]: http://go.microsoft.com/fwlink/p/?LinkID=268374
[Mobile Services SDK]: http://go.microsoft.com/fwlink/p/?LinkID=268375
[Developer Code Samples site]: http://go.microsoft.com/fwlink/p/?LinkId=271146
[System Properties]: http://go.microsoft.com/fwlink/?LinkId=331143
================================================
FILE: docs/mobile-services-windows-store-dotnet-handling-conflicts-offline-data.md
================================================
# Handling conflicts with offline data sync in Mobile Services
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
> [AZURE.SELECTOR-LIST (Platform | Backend)]
- [(iOS | Any)](mobile-services-ios-handling-conflicts-offline-data.md)
- [(Windows Runtime 8.1 universal C# | Any)](mobile-services-windows-store-dotnet-handling-conflicts-offline-data.md)
## Overview
This topic shows you how to synchronize data and handle conflicts when using the offline capabilities of Azure Mobile Services.
If you prefer to watch a video, the clip below follows the same steps as this tutorial.
> [AZURE.VIDEO build-offline-apps-with-mobile-services]
In this tutorial, you download a universal Windows C# solution for an app that supports handling offline synchronization conflicts. You will integrate a mobile service with the app, and then run the Windows Store 8.1 and Windows Phone 8.1 clients to generate a sync conflict and resolve it.
This tutorial builds on the steps and the sample app from the previous tutorial [Get started with offline data]. Before you begin this tutorial, you should first complete [Get started with offline data].
## Prerequisites
This tutorial requires Visual Studio 2013 running on Windows 8.1.
## Download the sample project
![][0]
This tutorial is a walkthrough of how the [Todo Offline Mobile Services sample] handles sync conflicts between the local offline store and the Mobile Service database in Azure.
1. Download the zip file for the [Mobile Services Samples GitHub Repository] and extract it to a working directory.
2. If you haven't already installed SQLite for Windows 8.1 and Windows Phone 8.1 as mentioned in the [Get started with offline data] tutorial, install both runtimes.
3. In Visual Studio 2013, open the *mobile-services-samples\TodoOffline\WindowsUniversal\TodoOffline-Universal.sln* solution file. Press the **F5** key to rebuild and run the project. Verify the NuGet packages are restored and the references are correctly set.
>[AZURE.NOTE] You may need to delete any old references to the SQLite runtime and replace them with the updated reference as mentioned in the [Get started with offline data] tutorial.
4. In the app, type some text in **Insert a TodoItem**, then click **Save** to add some todo items to the local store. Then close the app.
Note that the app is not yet connected to any mobile service, so the buttons **Push** and **Pull** will throw exceptions.
## Test the app against your mobile service
Now it's time to test the app against Mobile Services.
1. In the [Azure classic portal], find your mobile service's application key by clicking **Manage Keys** on the command bar of the **Dashboard** tab. Copy the **Application Key**.
2. In Solution Explorer for Visual Studio, open the App.xaml.cs file in the client sample project. Change the initialization of the **MobileServiceClient** to use your mobile service URL and application key:
public static MobileServiceClient MobileService = new MobileServiceClient(
"https://your-mobile-service.azure-mobile.net/",
"Your AppKey"
);
3. In Visual Studio, press the **F5** key to build and run the app again.
![][0]
## Update the data in the backend to create a conflict
In a real world scenario, a sync conflict would occur when one app pushes updates to a record in the database, and then another app tries to push an update to the same record using an outdated version field in that record. If you recall from the [Get started with offline data], the version system property is required to support the offline syncing features. This version information is examined with each database update. If an instance of the app tries to update a record using an outdated version, a conflict will occur and be caught as a `MobileServicePreconditionFailedException` in the app. If the app doesn't catch the `MobileServicePreconditionFailedException` then a `MobileServicePushFailedException` will end up being thrown describing how many sync errors were encountered.
>[AZURE.NOTE] To support synchronization of deleted records with offline data sync, you should enable [Soft Delete](mobile-services-using-soft-delete.md). Otherwise, you have to manually remove records in the local store, or call `IMobileServiceSyncTable::PurgeAsync()` to purge the local store.
The following steps show the Windows Phone 8.1 and Windows Store 8.1 clients running at the same time to cause and resolve a conflict using the sample.
1. In Visual Studio, right click the Windows Phone 8.1 project and click **Set as Startup Project**. Then press **Ctrl+F5** keys to run the Windows Phone 8.1 client without debugging. Once you have the Windows Phone 8.1 client up and running in the emulator, click the **Pull** button to sync the local store with the current state of the database.
![][3]
2. In Visual Studio, right click the Windows 8.1 runtime project and click **Set as Startup Project** to set it back to the start up project. Then press **F5** to run it. Once you have the Windows Store 8.1 client up and running, click the **Pull** button to sync the local store with the current state of the database.
![][4]
3. At this point point both clients are synchronized with the database. The code for both clients are also using incremental sync, so that they will only sync incomplete todo items. Completed todo items will be ignored. Choose one of the items and edit the text of the same item in both clients to a different value. Click the **Push** button to sync both changes with the database on the server.
![][5]
![][6]
4. The client whose push was executing last encounters the conflict and allows the user to decide which value to commit to the database. The exception provides the correct version value which is used for resolving the conflict.
![][7]
## Review of the code for handling sync conflicts
In order to use the offline features for Mobile Services, you must include the version column in both your local database and your data transfer object. This is accomplished by updating the `TodoItem` class the following member:
[Version]
public string Version { get; set; }
The `__version` column is included in the local database in the `OnNavigatedTo()` method when the `TodoItem` class is used to define the local store.
To handle offline sync conflicts in your code, you create a class that implements `IMobileServiceSyncHandler`. Pass an object of this type in the call to `MobileServiceClient.SyncContext.InitializeAsync()`. This also occurs in the `OnNavigatedTo()` method of the sample.
await App.MobileService.SyncContext.InitializeAsync(store, new SyncHandler(App.MobileService));
The class `SyncHandler` in **SyncHandler.cs** implements `IMobileServiceSyncHandler`. The method `ExecuteTableOperationAsync` is called when each push operation is sent to the server. If an exception of type `MobileServicePreconditionFailedException` is thrown, this means that there is a conflict between the local and remote versions of an item.
To resolve conflicts in favor of the local item, you should simply retry the operation. Once a conflict has occurred, the local item version will be updated to match the server version, so executing the operation again will overwrite the server changes with the local changes:
await operation.ExecuteAsync();
To resolve conflicts in favor of the server item, simply return from the `ExecuteTableOperationAsync`. The local version of the object will be discarded and replaced with the value from the server.
To stop the push operation (but retain the queued changes), use the method `AbortPush()`:
operation.AbortPush();
This will stop the current push operation but will keep all pending changes, including the current operation if `AbortPush` is called from `ExecuteTableOperationAsync`. The next time that `PushAsync()` is called, these changes will be sent to the server.
When a push is canceled, `PushAsync` will throw a `MobileServicePushFailedException`, and the exception property `PushResult.Status` will have the value `MobileServicePushStatus.CancelledByOperation`.
[0]: ./media/mobile-services-windows-store-dotnet-handling-conflicts-offline-data/mobile-services-handling-conflicts-app-run1.png
[1]: ./media/mobile-services-windows-store-dotnet-handling-conflicts-offline-data/javascript-backend-database.png
[2]: ./media/mobile-services-windows-store-dotnet-handling-conflicts-offline-data/dotnet-backend-database.png
[3]: ./media/mobile-services-windows-store-dotnet-handling-conflicts-offline-data/wp81-view.png
[4]: ./media/mobile-services-windows-store-dotnet-handling-conflicts-offline-data/win81-view.png
[5]: ./media/mobile-services-windows-store-dotnet-handling-conflicts-offline-data/wp81-edit-text.png
[6]: ./media/mobile-services-windows-store-dotnet-handling-conflicts-offline-data/win81-edit-text.png
[7]: ./media/mobile-services-windows-store-dotnet-handling-conflicts-offline-data/conflict.png
[Handling conflicts code sample]: http://go.microsoft.com/fwlink/?LinkId=394787
[Get started with Mobile Services]: mobile-services-windows-store-get-started.md
[Get started with offline data]: mobile-services-windows-store-dotnet-get-started-offline-data.md
[SQLite for Windows 8.1]: http://go.microsoft.com/fwlink/?LinkId=394776
[Azure classic portal]: https://manage.windowsazure.com/
[Handling Database Conflicts]: mobile-services-windows-store-dotnet-handle-database-conflicts.md#test-app
[Mobile Services Samples GitHub Repository]: http://go.microsoft.com/fwlink/?LinkId=512865
[Todo Offline Mobile Services sample]: http://go.microsoft.com/fwlink/?LinkId=512866
================================================
FILE: docs/mobile-services-xamarin-android-get-started-offline-data.md
================================================
# Using offline data sync in Mobile Services
> [AZURE.SELECTOR]
- [Android)](mobile-services-android-get-started-offline-data.md)
- [iOS](mobile-services-ios-get-started-offline-data.md)
- [Windows](mobile-services-windows-store-dotnet-get-started-offline-data.md)
- [Xamarin.Android](mobile-services-xamarin-android-get-started-offline-data.md)
- [Xamarin.iOS](mobile-services-xamarin-ios-get-started-offline-data.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This topic walks through the offline sync capabilities of Azure Mobile Services in the todo list quickstart app. Offline sync allows you to easily create apps that are usable even when the end user has no network access.
Offline sync has several potential uses:
* Improve app responsiveness by caching server data locally on the device
* Make apps resilient against intermittent network connectivity
* Allow end-users to create and modify data even when there is no network access, supporting scenarios with little or no connectivity
* Sync data across multiple devices and detect conflicts when the same record is modified by two devices
>[AZURE.NOTE] To complete this tutorial, you need a Azure account. If you don't have an account, you can sign up for an Azure trial and get up to 10 free mobile services that you can keep using even after your trial ends. For details, see Azure Free Trial.
>
> If this is your first experience with Mobile Services, you should first complete [Get started with Mobile Services].
This tutorial walks you through these basic steps:
1. [Review the Mobile Services sync code]
2. [Update the sync behavior of the app]
3. [Update the app to reconnect your mobile service]
This tutorial requires the following:
* Visual Studio with Xamarin on Windows or Xamarin Studio on Mac OS X. Complete installation instructions are on [Setup and Install for Visual Studio and Xamarin](https://msdn.microsoft.com/library/mt613162.aspx).
* Completion of the [Get started with Mobile Services] tutorial.
## Review the Mobile Services sync code
Azure Mobile Services offline sync allows end users to interact with a local database when the network is not accessible. To use these features in your app, you initialize `MobileServiceClient.SyncContext` to a local store. Then reference your table through the `IMobileServiceSyncTable` interface.
This section walks through the offline sync related code in `ToDoActivity.cs`.
1. In Visual Studio or Xamarin Studio, open the project that you completed in the [Get started with Mobile Services] tutorial. Open the file `ToDoActivity.cs`.
2. Notice the type of the member `toDoTable` is `IMobileServiceSyncTable`. Offline sync uses this sync table interface instead of `IMobileServiceTable`. When a sync table is used, all operations go to the local store and are only synchronized with the remote service with explicit push and pull operations.
To get a reference to a sync table, the method `GetSyncTable()` is used. To remove the offline sync functionality, you would instead use `GetTable()`.
3. Before any table operations can be performed, the local store must be initialized. This is done in the `InitLocalStoreAsync` method:
private async Task InitLocalStoreAsync()
{
// new code to initialize the SQLite store
string path = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), localDbFilename);
if (!File.Exists(path))
{
File.Create(path).Dispose();
}
var store = new MobileServiceSQLiteStore(path);
store.DefineTable();
// Uses the default conflict handler, which fails on conflict
await client.SyncContext.InitializeAsync(store);
}
This creates a local store using the class `MobileServiceSQLiteStore`, which is provided in the Mobile Services SDK. You can also a provide a different local store implementation by implementing `IMobileServiceLocalStore`.
The `DefineTable` method creates a table in the local store that matches the fields in the provided type, `ToDoItem` in this case. The type doesn't have to include all of the columns that are in the remote database--it is possible to store just a subset of columns.
This overload of `InitializeAsync` uses the default conflict handler, which fails whenever there is a conflict. To provide a custom conflict handler, see the tutorial [Handling conflicts with offline support for Mobile Services].
4. The method `SyncAsync` triggers the actual sync operation:
private async Task SyncAsync()
{
await client.SyncContext.PushAsync();
await toDoTable.PullAsync("allTodoItems", toDoTable.CreateQuery()); // query ID is used for incremental sync
}
First, there is a call to `IMobileServiceSyncContext.PushAsync()`. This method is a member of `IMobileServicesSyncContext` instead of the sync table because it will push changes across all tables. Only records that have been modified in some way locally (through CUD operations) will be sent to the server.
Next, the method calls `IMobileServiceSyncTable.PullAsync()` to pull data from a table on the server to the app. Note that if there are any changes pending in the sync context, a pull always issues a push first. This is to ensure all tables in the local store along with relationships are consistent. In this case, we have called push explicitly.
In this example, we retrieve all records in the remote `TodoItem` table, but it is also possible to filter records by passing a query. The first parameter to `PullAsync()` is a query ID that is used for incremental sync, which uses the `UpdatedAt` timestamp to get only those records modified since the last sync. The query ID should be a descriptive string that is unique for each logical query in your app. To opt-out of incremental sync, pass `null` as the query ID. This will retrieve all records on each pull operation, which is potentially inefficient.
>[AZURE.NOTE] To remove records from the device local store when they have been deleted in your mobile service database, you should enable [Soft Delete]. Otherwise, your app should periodically call `IMobileServiceSyncTable.PurgeAsync()` to purge the local store.
Note that the `MobileServicePushFailedException` can occur for both a push and a pull operation. The next tutorial, [Handling conflicts with offline support for Mobile Services], shows how to handle these sync related exceptions.
5. In the class `ToDoActivity`, the method `SyncAsync()` is called after the operations that modify data, `AddItem()` and `CheckItem()`. It is also called from `OnRefreshItemsSelected()`, so that users get the latest data whenever they push the **Refresh** button. The app also performs a sync on launch, since `ToDoActivity.OnCreate()` calls `OnRefreshItemsSelected()`.
Because `SyncAsync()` is called whenever data is modified, this app assumes that the user is online whenever they are editing data. In the next section, we will update the app so that users can edit even when they are offline.
## Update the sync behavior of the app
In this section, you will modify the app so that it does not sync on app launch or on the insert and update operations, but only when the refresh button is pushed. Then, you will break the app connection with the mobile service to simulate an offline scenario. When you add data items, they will be held in the local store, but not immediately synced to the mobile service.
1. In the class `ToDoActivity`, edit the methods `AddItem()` and `CheckItem()` to comment out the calls to `SyncAsync()`.
2. In `ToDoActivity`, comment out the definitions of the members `applicationURL` and `applicationKey`. Add the following lines, which reference an invalid mobile service URL:
const string applicationURL = @"https://your-mobile-service.azure-mobile.xxx/";
const string applicationKey = @"AppKey";
3. In `ToDoActivity.OnCreate()`, remove the call to `OnRefreshItemsSelected()` and replace with:
// Load the items from the Mobile Service
// OnRefreshItemsSelected (); // don't sync on app launch
await RefreshItemsFromTableAsync(); // load UI only
4. Build and run the app. Add some new todo items. These new items exist only in the local store until they can be pushed to the mobile service. The client app behaves as if is connected to the mobile service supporting all create, read, update, delete (CRUD) operations.
5. Close the app and restart it to verify that the new items you created are persisted to the local store.
## Update the app to reconnect your mobile service
In this section you will reconnect the app to the mobile service. This simulates the app moving from an offline state to an online state with the mobile service. When you push the **Refresh** button, data will be synced to your mobile service.
1. Open `ToDoActivity.cs`. Remove the invalid mobile service URL and add back the correct URL and app key.
2. Rebuild and run the app. Notice that the data looks the same as the offline scenario even though the app is now connected to the mobile service. This is because this app always uses the `IMobileServiceSyncTable` that is pointed to the local store.
3. Log into the [Azure classic portal] and look at the database for your mobile service. If your service uses the JavaScript backend, you can browse the data from the **Data** tab of the mobile service.
If you are using the .NET backend for your mobile service, in Visual Studio go to **Server Explorer** > **Azure** > **SQL Databases**. Right click your database and select **Open in SQL Server Object Explorer**.
Notice the data has *not* been synchronized between the database and the local store.
4. In the app, push the refresh button. This calls `OnRefreshItemsSelected()`, which in turn calls `SyncAsync()`. This will perform the push and pull operations, first sending the local store items to the mobile service, then retrieving new data from the service.
5. Check the database for your mobile service to confirm that changes have been synchronized.
## Summary
In order to support the offline features of mobile services, we used the `IMobileServiceSyncTable` interface and initialized `MobileServiceClient.SyncContext` with a local store. In this case the local store was a SQLite database.
The normal CRUD operations for mobile services work as if the app is still connected but, all the operations occur against the local store.
When we wanted to synchronize the local store with the server, we used the `IMobileServiceSyncTable.PullAsync` and `MobileServiceClient.SyncContext.PushAsync` methods.
* To push changes to the server, we called `IMobileServiceSyncContext.PushAsync()`. This method is a member of `IMobileServicesSyncContext` instead of the sync table because it will push changes across all tables.
Only records that have been modified in some way locally (through CUD operations) will be sent to the server.
* To pull data from a table on the server to the app, we called `IMobileServiceSyncTable.PullAsync`.
A pull always issues a push first. This is to ensure all tables in the local store along with relationships remain consistent.
There are also overloads of `PullAsync()` that allow a query to be specified in order to filter the data that is stored on the client. If a query is not passed, `PullAsync()` will pull all rows in the corresponding table (or query). You can pass the query to filter only the changes your app needs to sync with.
* To enable incremental sync, pass a query ID to `PullAsync()`. The query ID is used to store the last updated timestamp from the results of the last pull operation. The query ID should be a descriptive string that is unique for each logical query in your app. If the query has a parameter, then the same parameter value has to be part of the query ID.
For instance, if you are filtering on userid, it needs to be part of the query ID:
await PullAsync("todoItems" + userid, syncTable.Where(u => u.UserId = userid));
If you want to opt out of incremental sync, pass `null` as the query ID. In this case, all records will be retrieved on every call to `PullAsync`, which is potentially inefficient.
* To remove records from the device local store when they have been deleted in your mobile service database, you should enable [Soft Delete]. Otherwise, your app should periodically call `IMobileServiceSyncTable.PurgeAsync()` to purge the local store.
## Next steps
* [Handling conflicts with offline support for Mobile Services]
* [How to use the Xamarin Component client for Azure Mobile Services]
[Review the Mobile Services sync code]: #review-offline
[Update the sync behavior of the app]: #update-sync
[Update the app to reconnect your mobile service]: #update-online-app
[Handling conflicts with offline support for Mobile Services]: mobile-services-windows-store-dotnet-handling-conflicts-offline-data.md
[Get started with Mobile Services]: mobile-services-android-get-started.md
[How to use the Xamarin Component client for Azure Mobile Services]: partner-xamarin-mobile-services-how-to-use-client-library.md
[Soft Delete]: mobile-services-using-soft-delete.md
[Mobile Services SDK Nuget]: http://www.nuget.org/packages/WindowsAzure.MobileServices/1.3.0
[SQLite store nuget]: http://www.nuget.org/packages/WindowsAzure.MobileServices.SQLiteStore/1.0.0
[Azure classic portal]: https://manage.windowsazure.com
================================================
FILE: docs/mobile-services-xamarin-ios-get-started-offline-data.md
================================================
# Using offline data sync in Mobile Services
> [AZURE.SELECTOR]
- [Android)](mobile-services-android-get-started-offline-data.md)
- [iOS](mobile-services-ios-get-started-offline-data.md)
- [Windows](mobile-services-windows-store-dotnet-get-started-offline-data.md)
- [Xamarin.Android](mobile-services-xamarin-android-get-started-offline-data.md)
- [Xamarin.iOS](mobile-services-xamarin-ios-get-started-offline-data.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This topic walks through the offline sync capabilities of Azure Mobile Services in the todo list quickstart app. Offline sync allows you to easily create apps that are usable even when the end user has no network access.
Offline sync has several potential uses:
* Improve app responsiveness by caching server data locally on the device
* Make apps resilient against intermittent network connectivity
* Allow end-users to create and modify data even when there is no network access, supporting scenarios with little or no connectivity
* Sync data across multiple devices and detect conflicts when the same record is modified by two devices
>[AZURE.NOTE] To complete this tutorial, you need a Azure account. If you don't have an account, you can sign up for an Azure trial and get up to 10 free mobile services that you can keep using even after your trial ends. For details, see Azure Free Trial.
>
> If this is your first experience with Mobile Services, you should first complete [Get started with Mobile Services].
This tutorial walks you through these basic steps:
1. [Review the Mobile Services sync code]
2. [Update the sync behavior of the app]
3. [Update the app to reconnect your mobile service]
This tutorial requires the following:
* Visual Studio with Xamarin. See [Setup and install for Visual Studio and Xamarin](https://msdn.microsoft.com/library/mt613162.aspx) for instructions.
* A Mac with Xcode v7.0 or later and Xamarin Studio Community installed. See [Setup and install for Visual Studio and Xamarin](https://msdn.microsoft.com/library/mt613162.aspx) and [Setup, install, and verifications for Mac users](https://msdn.microsoft.com/library/mt488770.aspx) (MSDN).
* Completion of the [Get started with Mobile Services] tutorial.
## Review the Mobile Services sync code
Azure Mobile Services offline sync allows end users to interact with a local database when the network is not accessible. To use these features in your app, you initialize `MobileServiceClient.SyncContext` to a local store. Then reference your table through the `IMobileServiceSyncTable` interface.
This section walks through the offline sync related code in `QSTodoService.cs`.
1. In Visual Studio, open the project that you completed in the [Get started with Mobile Services] tutorial. Open the file `QSTodoService.cs`.
2. Notice the type of the member `todoTable` is `IMobileServiceSyncTable`. Offline sync uses this sync table interface instead of `IMobileServiceTable`. When a sync table is used, all operations go to the local store and are only synchronized with the remote service with explicit push and pull operations.
To get a reference to a sync table, the method `GetSyncTable()` is used. To remove the offline sync functionality, you would instead use `GetTable()`.
3. Before any table operations can be performed, the local store must be initialized. This is done in the `InitializeStoreAsync` method:
public async Task InitializeStoreAsync()
{
var store = new MobileServiceSQLiteStore(localDbPath);
store.DefineTable();
// Uses the default conflict handler, which fails on conflict
await client.SyncContext.InitializeAsync(store);
}
This creates a local store using the class `MobileServiceSQLiteStore`, which is provided in the Mobile Services SDK. You can also provide a different local store implementation by implementing `IMobileServiceLocalStore`.
The `DefineTable` method creates a table in the local store that matches the fields in the provided type, `ToDoItem` in this case. The type doesn't have to include all of the columns that are in the remote database--it is possible to store just a subset of columns.
This overload of `InitializeAsync` uses the default conflict handler, which fails whenever there is a conflict. To provide a custom conflict handler, see the tutorial [Handling conflicts with offline support for Mobile Services].
4. The method `SyncAsync` triggers the actual sync operation:
public async Task SyncAsync()
{
try
{
await client.SyncContext.PushAsync();
await todoTable.PullAsync("allTodoItems", todoTable.CreateQuery()); // query ID is used for incremental sync
}
catch (MobileServiceInvalidOperationException e)
{
Console.Error.WriteLine(@"Sync Failed: {0}", e.Message);
}
}
First, there is a call to `IMobileServiceSyncContext.PushAsync()`. This method is a member of `IMobileServicesSyncContext` instead of the sync table because it will push changes across all tables. Only records that have been modified in some way locally (through CUD operations) will be sent to the server.
Next, the method calls `IMobileServiceSyncTable.PullAsync()` to pull data from a table on the server to the app. Note that if there are any changes pending in the sync context, a pull always issues a push first. This is to ensure all tables in the local store along with relationships are consistent. In this case, we have called push explicitly.
In this example, we retrieve all records in the remote `TodoItem` table, but it is also possible to filter records by passing a query. The first parameter to `PullAsync()` is a query ID that is used for incremental sync, which uses the `UpdatedAt` timestamp to get only those records modified since the last sync. The query ID should be a descriptive string that is unique for each logical query in your app. To opt-out of incremental sync, pass `null` as the query ID. This will retrieve all records on each pull operation, which is potentially inefficient.
>[AZURE.NOTE] To remove records from the device local store when they have been deleted in your mobile service database, you should enable [Soft Delete]. Otherwise, your app should periodically call `IMobileServiceSyncTable.PurgeAsync()` to purge the local store.
Note that the `MobileServicePushFailedException` can occur for both a push and a pull operation. The next tutorial, [Handling conflicts with offline support for Mobile Services], shows how to handle these sync related exceptions.
5. In the class `QSTodoService`, the method `SyncAsync()` is called after the operations that modify data, `InsertTodoItemAsync()` and `CompleteItemAsync`. It is also called from `RefreshDataAsync()`, so that the user gets the latest data whenever they perform the refresh gesture. The app also performs a sync on launch, since `QSTodoListViewController.ViewDidLoad()` calls `RefreshDataAsync()`.
Because `SyncAsync()` is called whenever data is modified, this app assumes that the user is online whenever they are editing data. In the next section, we will update the app so that users can edit even when they are offline.
## Update the sync behavior of the app
In this section, you will modify the app so that it does not sync on app launch or on the insert and update operations, but only when the refresh gesture is performed. Then, you will break the app connection with the mobile service to simulate an offline scenario. When you add data items, they will be held in the local store, but not immediately synced to the mobile service.
1. Open `QSTodoService.cs`. Comment out the calls to `SyncAsync()` in the following methods:
- `InsertTodoItemAsync`
- `CompleteItemAsync`
- `RefreshDataAsync`
Now, `RefreshAsync()` will only load data from the local store, but will not connect to the app backend.
2. In `QSTodoService.cs`, comment out the definitions of the members `applicationURL` and `applicationKey`. Add the following lines, which reference an invalid mobile service URL:
const string applicationURL = @"https://your-mobile-service.azure-mobile.xxx/";
const string applicationKey = @"AppKey";
3. To ensure that data is synchronized when the refresh gesture is performed, edit the method `QSTodoListViewController.RefreshAsync()`. Add a call to `SyncAsync()` before the call to `RefreshDataAsync()`:
private async Task RefreshAsync ()
{
RefreshControl.BeginRefreshing ();
await todoService.SyncAsync();
await todoService.RefreshDataAsync (); // add this line
RefreshControl.EndRefreshing ();
TableView.ReloadData ();
}
4. Build and run the app. Add some new todo items. These new items exist only in the local store until they can be pushed to the mobile service. The client app behaves as if is connected to the mobile service supporting all create, read, update, delete (CRUD) operations.
5. Close the app and restart it to verify that the new items you created are persisted to the local store.
## Update the app to reconnect your mobile service
In this section you will reconnect the app to the mobile service. This simulates the app moving from an offline state to an online state with the mobile service. When you perform the refresh gesture, data will be synced to your mobile service.
1. Open `QSTodoService.cs`. Remove the invalid mobile service URL and add back the correct URL and app key.
2. Rebuild and run the app. Notice that the data looks the same as the offline scenario even though the app is now connected to the mobile service. This is because this app always uses the `IMobileServiceSyncTable` that is pointed to the local store.
3. Log into the [Azure classic portal] and look at the database for your mobile service. If your service uses the JavaScript backend, you can browse the data from the **Data** tab of the mobile service.
If you are using the .NET backend for your mobile service, in Visual Studio go to **Server Explorer** > **Azure** > **SQL Databases**. Right click your database and select **Open in SQL Server Object Explorer**.
Notice the data has *not* been synchronized between the database and the local store.
4. In the app, perform the refresh gesture by pulling down the list of items. This causes the app to call `RefreshDataAsync()`, which in turn calls `SyncAsync()`. This will perform the push and pull operations, first sending the local store items to the mobile service, then retrieving new data from the service.
5. Check the database for your mobile service to confirm that changes have been synchronized.
## Summary
In order to support the offline features of mobile services, we used the `IMobileServiceSyncTable` interface and initialized `MobileServiceClient.SyncContext` with a local store. In this case the local store was a SQLite database.
The normal CRUD operations for mobile services work as if the app is still connected but, all the operations occur against the local store.
When we wanted to synchronize the local store with the server, we used the `IMobileServiceSyncTable.PullAsync` and `MobileServiceClient.SyncContext.PushAsync` methods.
* To push changes to the server, we called `IMobileServiceSyncContext.PushAsync()`. This method is a member of `IMobileServicesSyncContext` instead of the sync table because it will push changes across all tables.
Only records that have been modified in some way locally (through CUD operations) will be sent to the server.
* To pull data from a table on the server to the app, we called `IMobileServiceSyncTable.PullAsync`.
A pull always issues a push first. This is to ensure all tables in the local store along with relationships remain consistent.
There are also overloads of `PullAsync()` that allow a query to be specified in order to filter the data that is stored on the client. If a query is not passed, `PullAsync()` will pull all rows in the corresponding table (or query). You can pass the query to filter only the changes your app needs to sync with.
* To enable incremental sync, pass a query ID to `PullAsync()`. The query ID is used to store the last updated timestamp from the results of the last pull operation. The query ID should be a descriptive string that is unique for each logical query in your app. If the query has a parameter, then the same parameter value has to be part of the query ID.
For instance, if you are filtering on userid, it needs to be part of the query ID:
await PullAsync("todoItems" + userid, syncTable.Where(u => u.UserId = userid));
If you want to opt out of incremental sync, pass `null` as the query ID. In this case, all records will be retrieved on every call to `PullAsync`, which is potentially inefficient.
* To remove records from the device local store when they have been deleted in your mobile service database, you should enable [Soft Delete]. Otherwise, your app should periodically call `IMobileServiceSyncTable.PurgeAsync()` to purge the local store.
## Next steps
* [How to use the Xamarin Component client for Azure Mobile Services]
[Review the Mobile Services sync code]: #review-offline
[Update the sync behavior of the app]: #update-sync
[Update the app to reconnect your mobile service]: #update-online-app
[Handling conflicts with offline support for Mobile Services]: mobile-services-xamarin-ios-handling-conflicts-offline-data.md
[Get started with Mobile Services]: mobile-services-ios-get-started.md
[How to use the Xamarin Component client for Azure Mobile Services]: partner-xamarin-mobile-services-how-to-use-client-library.md
[Soft Delete]: mobile-services-using-soft-delete.md
[Azure classic portal]: https://manage.windowsazure.com
================================================
FILE: docs/partner-sencha-mobile-services-get-started.md
================================================
# Get started with Mobile Services and Sencha Touch
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal JavaScript | Javascript)](mobile-services-javascript-backend-windows-store-javascript-get-started.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started.md)
- [(Android | Javascript)](mobile-services-android-get-started.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started.md)
- [(HTML | Javascript)](mobile-services-html-get-started.md)
- [(PhoneGap | Javascript)](mobile-services-javascript-backend-phonegap-get-started.md)
- [(Sencha | Javascript)](partner-sencha-mobile-services-get-started.md)
>[AZURE.TIP] This topic shows you how to get started with Mobile Services as quickly as possible. It is designed for customers new to this Azure feature. If you are already familiar with Mobile Services or are looking for more in-depth information, please select a topic from the left-navigation or see the relevant links in [Next steps](#next-steps).
## Overview
This tutorial shows you how to leverage Azure Mobile Services in your Sencha Touch application. You will create a simple *To Do List* app using Sencha Touch that utilizes a mobile service you define through the Azure classic portal. This tutorial is intended for intermediate to advanced web application developers who have a good understanding of JavaScript and who are familiar with the Sencha Touch framework.
If you prefer to watch a video, this clip follows the same steps as this tutorial. In the video, Arthur Kay explains how to build a Sencha Touch application using an Azure Mobile Services backend.
> [AZURE.VIDEO getting-started-with-sencha-touch]
A screenshot from the completed app is shown below:
![][0]
## Requirements
- Download and install [Sencha Touch](http://wwww.sencha.com/products/touch/download" target="_blank").
- Download and install [Sencha Cmd Tool](http://www.sencha.com/products/sencha-cmd/download" target="_blank").
- Java Runtime Environment (JRE), or Java Development Kit (if you are creating Android apps)
- Ruby and SASS gem.
## Create a new mobile service
Follow these steps to create a new mobile service.
1. Log into the [Azure classic portal](https://manage.windowsazure.com/). At the bottom of the navigation pane, click **+NEW**. Expand **Compute** and **Mobile Service**, then click **Create**.

This displays the **Create a Mobile Service** dialog.
2. In the **Create a Mobile Service** dialog, select **Create a free 20 MB SQL Database**, select **JavaScript** runtime, then type a subdomain name for the new mobile service in the **URL** textbox. Click the right arrow button to go to the next page.

This displays the **Specify database settings** page.
>[AZURE.NOTE]As part of this tutorial, you create a new SQL Database instance and server. You can reuse this new database and administer it as you would any other SQL Database instance. If you already have a database in the same region as the new mobile service, you can instead choose **Use existing Database** and then select that database. The use of a database in a different region is not recommended because of additional bandwidth costs and higher latencies.
3. In **Name**, type the name of the new database, then type **Login name**, which is the administrator login name for the new SQL Database server, type and confirm the password, and click the check button to complete the process.

You have now created a new mobile service that can be used by your mobile apps.
## Create a TodoItems Table
Once you have created your mobile service, you can follow an easy quickstart in the Azure classic portal to create
a new database table for use in your mobile service.
1. In the [Azure classic portal], click **Mobile Services**, and then click the mobile service that you just created.
2. In the quickstart tab, click **HTML** under **Choose platform** and expand **Create a new HTML app**.

This displays the three easy steps to create and host an HTML app connected to your mobile service.

3. Click **Create TodoItems table** to create a table to store app data.
> [AZURE.NOTE] Do NOT download the HTML app from the Azure classic portal. Instead, we will manually create a Sencha Touch application in the section below.
1. Take note of the **appKey** and **appUrl** in the Azure classic portal. You will use them in other sections of this tutorial.

1. In the **Configure** tab, verify that `localhost` is already listed in the **Allow requests from host names** list under **Cross-Origin Resource Sharing (CORS)**. If it's not, type `localhost` in the **Host name** field and then click **Save**.

## Generate your Touch application
Generating a Sencha Touch template application is a simple task using Sencha Cmd and is a great way to get an application up and running very quickly.
From the directory where you installed the Touch framework, issue the following command:
$ sencha generate app Basic /path/to/application
This generates a template Touch application with an application name of 'Basic'. To launch your application, simply point your browser to the directory /path/to/application and you should be presented with the standard Touch sample application.
## Installing the Sencha Touch Extensions for Azure
The extension for Azure is installed either manually or as a Sencha Package. The method you use is totally up to you.
### Manual installation
In most Touch applications, if you wish to add an external library of classes, you simply download the package, unpack it in your application directory and configure the Touch loader with the location of the library.
You can manually add the Azure extensions to your application using the following steps:
1. Download the Azure extensions package from [here](https://market.sencha.com/extensions/sencha-extensions-for-microsoft-azure). (You may use your Sencha Forums ID to access this area.)
2. Copy the Azure extensions package from the download directory to where you would ultimately want it to reside and unpack it :
$ cd /path/to/application
$ mv /download-location/azure.zip .
$ unzip azure.zip
This creates an **azure** directory containing the entire package source, examples and documentation. The source will reside in the **azure/src** directory.
### Installation as a Sencha package
> [AZURE.NOTE] You can only use this method when you have generated your application using the sencha generate app command.
All applications generated by Sencha Cmd have a "packages" folder at the root. The location of this folder can be configured, but regardless of its location, the role of the "packages" folder is to serve as the storage of all packages used by your application (or applications if you have created a Sencha Workspace).
As Ext.Azure is a Sencha Cmd "package", the source code can be easily installed and included in your application using Sencha Cmd. (See [Sencha Cmd Packages](http://docs.sencha.com/cmd/6.x/cmd_packages/cmd_packages.html) for more information).
To download and install the Azure extensions package from the Sencha Packages repository, you will need to add the package name to your **app.json** file and build your application:
1. Add the Azure package to the requires section of your app.json file:
{
"name": "Basic",
"requires": [
"touch-azure"
]
}
2. Rebuild your application using **sencha cmd** to fetch and install the package:
$ sencha app build
Both **sencha app build** and **sencha app refresh** will both now perform the steps needed to integrate the package in to your application. Typically, after changing package requirements, you will need to run **sencha app refresh** so that the metadata required to support "dev mode" is up to date.
Whichever command you run, Sencha Cmd will download and expand the package to your "packages" folder. After this you will find a "packages/touch-azure" folder in your workspace.
## Include and configure Azure
**Filename**: app.js
Now that the Azure extension has been downloaded and installed in your application directory, the next step is to tell your application where to find the source files, and to require those files:
1. Configure the Sencha Loader with the location of the source code:
Ext.Loader.setConfig({
enabled : true,
paths : {
'Ext' : 'touch/src',
'Ext.azure' : '/path-to/azure-for-touch/azure/src'
}
});
2. Require the Azure class files:
Ext.application({
requires: [ 'Ext.azure.Azure' ],
// ...
});
3. Configuring Azure
The Azure package is initialized by calling the **Ext.Azure.init** method in the launch section of your application. This method is passed a configuration object containing mobile service credentials as well as other credentials and features you wish to utilize.
While you can pass the configuration object directly to the init method, we suggest creating a Sencha application configuration property called **azure** and placing all the appropriate information there. You can then pass this property value to the Ext.Azure.init method.
When you create a mobile service in Azure (see [Getting Started with Azure](http://senchaazuredocs.azurewebsites.net/#!/guide/getting_started)), an application key and URL are assigned to that service. This information must be provided to your Azure package so it can connect to your service.
This example shows a very simple Azure configuration and initialization supplying only the application key and URL:
Ext.application({
name: 'Basic',
requires: [ 'Ext.azure.Azure' ],
azure: {
appKey: 'myazureservice-access-key',
appUrl: 'myazure-service.azure-mobile.net'
},
launch: function() {
// Call Azure initialization
Ext.Azure.init(this.config.azure);
}
});
For more information on the Azure configuration options, please consult the Ext.Azure API documentation.
Congratulations! Your application should now have access to your mobile service.
## Build the ToDo app
Now that we have configured your application to include the Azure extension, and provided it with your mobile service credentials, we can move on to creating a Touch application which utilizes your mobile service for viewing and editing your ToDo list data stored in the service.
### Configure the Azure data proxy
**Filename:** app/model/TodoItem.js
Your Touch application will be communicating with your mobile service via a data proxy. The proxy does all the work of both sending requests to, and receiving data from, the mobile service. Used in combination with a Touch data model and store, all the hard work of processing remote data and getting it into your application is removed and handled by Touch itself.
Sencha Touch models provide the definition of the data records you will be using in your application. They allow you to not only define the data fields but also provide configuration about the proxy that will be handling the communication between the application and the Azure mobile service.
In the code below you can see that we define the fields (and their types) for the model, and also provide a proxy configuration. When configuring your proxy, you need to give it a type (in this case 'azure'), the mobile service tablename (ToDoItem) and other optional parameters. In this example, we will be turning on proxy paging so that we can seamlessly page forward and backward through list items.
The Azure proxy will automatically set all HTTP headers with the appropriate CRUD operations expected by the Azure API (including authentication credentials, if they exist).
Ext.define('Basic.model.TodoItem', {
extend : 'Ext.data.Model',
requires : [
'Ext.azure.Proxy'
],
config : {
idProperty : 'id',
useCache : false,
fields : [
{
name : 'id',
type : 'int'
},
{
name : 'text',
type : 'string'
},
{
name : 'complete',
type : 'boolean'
}
],
proxy : {
type : 'azure',
tableName : 'TodoItem',
enablePagingParams : true
}
}
});
### Store your ToDo items
**Filename**: app/store/TodoItems.js
Sencha Touch stores are used to store collections of data records (models) which can be used as sources for Touch components for displaying the records in a variety of different ways. This can include Grids, Charts, Lists and more.
Here we define a store which will be used to hold all your store ToDo list items which are retrieved from your Azure mobile service. Notice that the store configuration contains the name of the model type (Basic.model.TodoItem - defined above). This defines the structure of the records which will be contained in the store.
We also have some additional configuration options for the store such as specifying the page size (8 records), and that the sorting of records for this store is done remotely by the Azure mobile service (no sorting is done locally within the store itself).
Ext.define('Basic.store.TodoItems', {
extend : 'Ext.data.Store',
requires : [
'Basic.model.TodoItem'
],
config : {
model : 'Basic.model.TodoItem',
pageSize : 8,
remoteSort : true,
remoteFilter : true
}
});
### View and edit your ToDo items
**Filename**: app/view/DataItem.js
Now that we have defined the structure of each ToDo item, and created a store to place all the records in, we should think about how we wish to display this information to the user of the app. We normally display information to the user through the use of **Views**. A view can be one of any number of Touch components, individually or combined with others.
The view below is comprised of a ListItem which defines how each record will be displayed along with some buttons which will accommodate actions to delete each item.
Ext.define('Basic.view.DataItem', {
extend : 'Ext.dataview.component.ListItem',
xtype : 'basic-dataitem',
requires : [
'Ext.Button',
'Ext.layout.HBox',
'Ext.field.Checkbox'
],
config : {
checkbox : {
docked : 'left',
xtype : 'checkboxfield',
width : 50,
labelWidth : 0
},
text : {
flex : 1
},
button : {
docked : 'right',
xtype : 'button',
ui : 'plain',
iconMask : true,
iconCls : 'delete',
style : 'color: red;'
},
dataMap : {
getText : {
setHtml : 'text'
},
getCheckbox : {
setChecked : 'complete'
}
},
layout : {
type : 'hbox',
align: 'stretch'
}
},
applyCheckbox : function(config) {
return Ext.factory(config, Ext.field.Checkbox, this.getCheckbox());
},
updateCheckbox : function (cmp) {
if (cmp) {
this.add(cmp);
}
},
applyButton : function(config) {
return Ext.factory(config, Ext.Button, this.getButton());
},
updateButton : function (cmp) {
if (cmp) {
this.add(cmp);
}
}
});
### Create your primary view
**Filename**: app/view/Main.js
Now that we have defined the layout of an individual ToDo list item (above) we want to wrap a full user interface around that list which defines the actual list of items, an application title, and a button to add a new task.
Ext.define('Basic.view.Main', {
extend : 'Ext.dataview.List',
xtype : 'main',
requires : [
'Ext.TitleBar',
'Ext.dataview.List',
'Ext.data.Store',
'Ext.plugin.PullRefresh',
'Ext.plugin.ListPaging',
'Basic.view.DataItem'
],
config : {
store : 'TodoItems',
useSimpleItems : false,
defaultType : 'basic-dataitem',
plugins : [
{
xclass : 'Ext.plugin.PullRefresh',
pullRefreshText : 'Pull down to refresh!'
},
{
xclass : 'Ext.plugin.ListPaging',
autoPaging : true
}
],
scrollable : {
direction : 'vertical',
directionLock : true
},
items : [
{
docked : 'top',
xtype : 'titlebar',
title : 'Azure Mobile - Basic Data Example'
},
{
xtype : 'toolbar',
docked : 'bottom',
items : [
{
xtype : 'textfield',
placeHolder : 'Enter new task',
flex : 1
},
{
xtype : 'button',
action : 'add',
text : 'Add'
}
]
}
]
}
});
### Make everything work together
**Filename**: app/controller/Main.js
The final step in our application is to respond to button presses (delete, save, etc) and provide the logic behind all these requests. Sencha Touch utilizes controllers which listen for these events and responds accordingly.
Ext.define('Basic.controller.Main', {
extend : 'Ext.app.Controller',
config : {
refs : {
todoField : 'main toolbar textfield',
main : 'main'
},
control : {
'button[action=add]' : {
tap : 'onAddItem'
},
'button[action=reload]' : {
tap : 'onReload'
},
main : {
activate : 'loadInitialData',
itemdoubletap : 'onItemEdit'
},
'basic-dataitem checkboxfield' : {
change : 'onItemCompleteTap'
},
'basic-dataitem button' : {
tap : 'onItemDeleteTap'
}
}
},
loadInitialData : function () {
Ext.getStore('TodoItems').load();
},
onItemDeleteTap : function (button, e, eOpts) {
var store = Ext.getStore('TodoItems'),
dataItem = button.up('dataitem'),
rec = dataItem.getRecord();
rec.erase({
success: function (rec, operation) {
store.remove(rec);
},
failure: function (rec, operation) {
Ext.Msg.alert(
'Error',
Ext.util.Format.format('There was an error deleting this task.
Status Code: {0} Status Text: {1}',
operation.error.status,
operation.error.statusText)
);
}
});
},
onItemCompleteTap : function (checkbox, newVal, oldVal, eOpts) {
var dataItem = checkbox.up('dataitem'),
rec = dataItem.getRecord(),
recVal = rec.get('complete');
// this check is needed to prevent an issue where multiple creates get triggered from one create
if (newVal !== recVal) {
rec.set('complete', newVal);
rec.save({
success: function (rec, operation) {
rec.commit();
},
failure: function (rec, operation) {
// since there was a failure doing the update on the server then silently reject the change
rec.reject(true);
Ext.Msg.alert(
'Error',
Ext.util.Format.format('There was an error updating this task.
Status Code: {0} Status Text: {1}',
operation.error.status,
operation.error.statusText)
);
}
});
}
},
onItemEdit : function (list, index, target, record, e, eOpts) {
var rec = list.getSelection()[0];
Ext.Msg.prompt('Edit', 'Rename task',
function (buttonId, value) {
if (buttonId === 'ok') {
rec.set('text', value);
rec.save({
success: function (rec, operation) {
rec.commit();
},
failure: function (rec, operation) {
// since there was a failure doing the update on the server then reject the change
rec.reject();
Ext.Msg.alert(
'Error',
Ext.util.Format.format('There was an error updating this task.
Status Code: {0} Status Text: {1}',
operation.error.status,
operation.error.statusText)
);
}
});
}
},
null,
false,
record.get('text')
);
},
onReload : function () {
Ext.getStore('TodoItems').load();
},
onAddItem : function () {
var me = this,
rec,
store = Ext.getStore('TodoItems'),
field = me.getTodoField(),
value = field.getValue();
if (value === '') {
Ext.Msg.alert('Error', 'Please enter Task name', Ext.emptyFn);
}
else {
rec = Ext.create('Basic.model.TodoItem', {
complete : false,
text : value
});
//store.insert(0, rec); //insert at the top
//store.sync();
rec.save({
success: function (rec, operation) {
store.insert(0, rec); //insert at the top
field.setValue('');
},
failure: function (rec, operation) {
Ext.Msg.alert(
'Error',
Ext.util.Format.format('There was an error creating this task.
Status Code: {0} Status Text: {1}',
operation.error.status,
operation.error.statusText)
);
}
});
}
}
});
### Put it all together
**Filename**: app.js
Our final step is to finish editing the main application file, and provide information about the models, stores, views and controllers that have defined. The source files for these resources are automatically loaded into the application. Finally, the launch method is called which creates and displays the primary application view 'Basic.main.View'.
Ext.Loader.setConfig({
enabled : true,
paths : {
'Ext' : 'touch/src',
'Ext.azure' : 'packages/azure/src'
}
});
Ext.application({
name : 'Basic',
requires : [
'Ext.MessageBox',
'Ext.azure.Azure'
],
views : [
'Main'
],
controllers : [
'Main'
],
stores : [
'TodoItems'
],
azure : {
appUrl : 'YOUR_APP_URL.azure-mobile.net',
appKey : 'YOUR_APP_KEY'
},
icon : {
'57' : 'resources/icons/Icon.png',
'72' : 'resources/icons/Icon~ipad.png',
'114' : 'resources/icons/Icon@2x.png',
'144' : 'resources/icons/Icon~ipad@2x.png'
},
isIconPrecomposed : true,
startupImage : {
'320x460' : 'resources/startup/320x460.jpg',
'640x920' : 'resources/startup/640x920.png',
'768x1004' : 'resources/startup/768x1004.png',
'748x1024' : 'resources/startup/748x1024.png',
'1536x2008' : 'resources/startup/1536x2008.png',
'1496x2048' : 'resources/startup/1496x2048.png'
},
launch : function () {
// Destroy the #appLoadingIndicator element
Ext.fly('appLoadingIndicator').destroy();
// Initialize Azure
Ext.Azure.init(this.config.azure);
// Initialize the main view
Ext.Viewport.add(Ext.create('Basic.view.Main'));
},
onUpdated : function () {
Ext.Msg.confirm(
"Application Update",
"This application has just successfully been updated to the latest version. Reload now?",
function (buttonId) {
if (buttonId === 'yes') {
window.location.reload();
}
}
);
}
});
### Host and run your Sencha Touch app
The final stage of this tutorial is to host and run your new app on your local computer.
1. In your terminal, browse to the location of your unzipped application.
2. Using Sencha Cmd, run the following commands:
* *sencha app refresh* : This will instruct Sencha Cmd to locate all app dependencies,
and download any needed packages (for example, [Sencha Touch Extensions for Azure](https://market.sencha.com/extensions/sencha-extensions-for-microsoft-azure)).
* *sencha web start* : This will start a local web server to test our application.

3. Open the URL listed in your terminal in a web browser to start the app (e.g. http://localhost:1841).
4. In the app, type meaningful text, such as "Complete the tutorial", and then click **Add**.

This sends a POST request to the new mobile service hosted in Azure. Data from the request is inserted into the TodoItem table.
5. Back in the [Azure classic portal], click the **Data** tab and then click the TodoItems table.

This lets you browse the data inserted by the app into the table.

## Next Steps
Now that you have completed the Getting Started Guide, learn how to perform additional important tasks in Mobile Services with Sencha.
[Download](https://github.com/arthurakay/sencha-touch-azure-example) a completed sample app with additional styling and features to see what else Sencha Touch can do!
Then, dive into more information about the Sencha Touch Extensions for Azure:
* Sample app [walkthrough](http://docs.sencha.com/touch-azure/1.0.0/#!/guide/data_filters)
* Get help in the [Sencha Forums](http://www.sencha.com/forum)
* Browse the [Sencha Documentation](http://docs.sencha.com/)
* Using Sencha With Azure Mobile Services: [(Video)](http://channel9.msdn.com/Shows/Cloud+Cover/Episode-126-Using-Sencha-With-Windows-Azure-Mobile-Services)
## Additional Resources
* [Download Sencha Touch](http://pages.sencha.com/touch-for-azure.html)
* [Sencha Touch Extensions for Azure](https://market.sencha.com/extensions/sencha-extensions-for-microsoft-azure)
## Summary
The example outlined here is provided in the Sencha Touch Extension for Azure package and is located in the examples directory as the Basic Data example. There are a few more examples which are provided which demonstrated other functionality of this extension along with detailed comments and explanations.
For more information about getting started with Sencha Touch please visit the full set of [guides](http://docs.sencha.com/touch/#!/guide)
[0]: ./media/partner-sencha-mobile-services-get-started/finished-app.png
[Azure classic portal]: https://manage.windowsazure.com/
================================================
FILE: docs/partner-twilio-mobile-services-how-to-use-voice-sms.md
================================================
# How to use Twilio for voice and SMS capabilities from Mobile Services
This topic shows you how to perform common tasks using the Twilio API with Azure Mobile Services. In this tutorial you will learn how to create Custom API scripts that use the Twilio API to initiate a phone call and to send a Short Message Service (SMS) message.
## What is Twilio?
Twilio is powering the future of business communications, enabling developers to embed voice, VoIP, and messaging into applications. They virtualize all infrastructure needed in a cloud-based, global environment, exposing it through the Twilio communications API platform. Applications are simple to build and scalable. Enjoy flexibility with pay-as-you go pricing, and benefit from cloud reliability.
**Twilio Voice** allows your applications to make and receive phone calls. **Twilio SMS** enables your applications to send and receive SMS messages. **Twilio Client** allows you to make VoIP calls from any phone, tablet, or browser and supports WebRTC.
## Twilio Pricing and Special Offers
Azure customers receive a [special offer][special_offer]: complimentary $10 of Twilio Credit when you upgrade your Twilio Account. This Twilio Credit can be applied to any Twilio usage ($10 credit equivalent to sending as many as 1,000 SMS messages or receiving up to 1000 inbound Voice minutes, depending on the location of your phone number and message or call destination). Redeem this Twilio credit and get started at [ahoy.twilio.com/azure][special_offer].
Twilio is a pay-as-you-go service. There are no set-up fees and you can close your account at any time. You can find more details at [Twilio Pricing][twilio_pricing].
## Concepts
The Twilio API is a RESTful API that provides voice and SMS functionality for applications. Client libraries are available in multiple languages.
Key aspects of the Twilio API are Twilio verbs and Twilio Markup Language (TwiML).
### Twilio verbs
The API makes use of Twilio verbs; for example, the **<Say>** verb instructs Twilio to audibly deliver a message on a call.
The following is a list of Twilio verbs. Learn about the other verbs and capabilities via [Twilio Markup Language documentation](http://www.twilio.com/docs/api/twiml).
* **<Dial>**: Connects the caller to another phone.
* **<Gather>**: Collects numeric digits entered on the telephone keypad.
* **<Hangup>**: Ends a call.
* **<Pause>**: Waits silently for a specified number of seconds.
* **<Play>**: Plays an audio file.
* **<Queue>**: Add the to a queue of callers.
* **<Record>**: Records the caller's voice and returns a URL of a file that contains the recording.
* **<Redirect>**: Transfers control of a call or SMS to the TwiML at a different URL.
* **<Reject>**: Rejects an incoming call to your Twilio number without billing you
* **<Say>**: Converts text to speech that is made on a call.
* **<Sms>**: Sends an SMS message.
### TwiML
TwiML is a set of XML-based instructions based on the Twilio verbs that inform Twilio of how to process a call or SMS.
As an example, the following TwiML would convert the text **Hello World** to speech.
Hello World
When your application calls the Twilio API, one of the API parameters is the URL that returns the TwiML response. For development purposes, you can use Twilio-provided URLs to provide the TwiML responses used by your applications. You could also host your own URLs to produce the TwiML responses, and another option is to use the `TwiMLResponse` object.
For more information about Twilio verbs, their attributes, and TwiML, see [TwiML][twiml]. For additional information about the Twilio API, see [Twilio API][twilio_api].
## Create a Twilio Account
When you're ready to get a Twilio account, sign up at [Try Twilio][try_twilio]. You can start with a free account, and upgrade your account later.
When you sign up for a Twilio account, you'll receive an account SID and an authentication token. Both will be needed to make Twilio API calls. To prevent unauthorized access to your account, keep your authentication token secure. Your account SID and authentication token are viewable in the [Twilio Console][twilio_console], in the fields labeled **ACCOUNT SID** and **AUTH TOKEN**, respectively.
## Create a Mobile Service
A Mobile Service that hosts a Twilio enabled application is no different from any other Mobile Service. You simply add the Twilio node.js library in order to reference it from your Mobile Service Custom API scripts. For information on creating an initial mobile service, see [Getting Started with Mobile Services](mobile-services-ios-get-started.md).
## Configure Your Mobile Service to use the Twilio Node.js Library
Twilio provides a Node.js library that wraps various aspects of Twilio to provide simple and easy ways to interact with the Twilio REST API and Twilio Client to generate TwiML responses.
To use the Twilio node.js library in your Mobile Service, you need leverage Mobile Services npm module support, which you can do by storing your scripts in source control.
1. Complete the tutorial [Store Scripts in Source Control](mobile-services-store-scripts-source-control.md). This walks you through setting-up source control for your Mobile Services and storing your server scripts in a Git repository.
2. After you have set up source control for your Mobile Service, open the repository on your local computer, browse to the `\services` subfolder, open the package.json file in a text editor, and add the following field to the **dependencies** object:
"twilio": "~2.11.1"
3. After you have added the Twilio package reference to the **dependencies** object, the package.json file should look like the following:
{
"name": "todolist",
"version": "1.0.0",
"description": "todolist - hosted on Azure Mobile Services",
"main": "server.js",
"engines": {
"node": ">= 0.8.19"
},
"dependencies": {
"twilio": "~2.11.1"
},
"devDependencies": {},
"scripts": {},
"author": "unknown",
"licenses": [],
"keywords":[]
}
>[AZURE.NOTE]The dependency for Twilio should be added as `"twilio": "~2.11.1"`, with a (~). A reference with a caret (^) is not supported.
4. Commit this file update and push the update back to the mobile service.
This update to the package.json file will restart your mobile service.
The mobile service now installs and loads the Twilio package so you can reference and use the Twilio library in your custom API and table scripts.
## How to: Make an outgoing call
The following script shows how to initiate an outgoing call from your Mobile Service using the **Call** resource. This code also uses a Twilio-provided site to return the Twilio Markup Language (TwiML) response. Substitute your values for the `from` and `to` phone numbers, and ensure that you verify the `from` phone number for your Twilio account before running the code.
var twilio = require('twilio');
exports.post = function(request, response) {
var client = new twilio.RestClient('ACCOUNT_SID', 'AUTH_TOKEN');
client.calls.create({
to:'+16515556677',
from: '+14506667788',
url: 'http://www.example.com/twiml.php'
}, function(err, responseData) {
console.log(responseData.from);
response.send(200, '');
});
};
For more information about the parameters passed in to the `client.calls.create` function, see [http://www.twilio.com/docs/api/rest/making-calls][twilio_rest_making_calls].
As mentioned, this code uses a Twilio-provided site to return the TwiML response. You could instead use your own site to provide the TwiML response. For more information, see [How to: Provide TwiML responses from your own web site](#howto_provide_twiml_responses).
## How to: Send an SMS message
The following code shows how to send an SMS message using the **Message** resource. The `from` number is provided by Twilio for trial accounts to send SMS messages. The `to` number must be verified for your Twilio account before you run the code.
var twilio = require('twilio');
exports.post = function(request, response) {
var client = new twilio.RestClient('ACCOUNT_SID', 'AUTH_TOKEN');
client.messages.create({
to:'+16515556677',
from:'+14506667788',
body:'ahoy hoy! Testing Twilio and node.js'
}, function(error, message) {
// The "error" variable will contain error information, if any.
// If the request was successful, this value will be "false"
if (!error) {
console.log('Success! The SID for this SMS message is: ' + message.sid);
console.log('Message sent on: ' + message.dateCreated);
}
else {
console.log('Oops! There was an error.');
}
response.send(200, { error : error } );
});
};
## How to: Provide TwiML responses from your own website
When your application initiates a call to the Twilio API, Twilio sends your request to a URL that is expected to return a TwiML response. The example in How to: Make an outgoing call uses the Twilio-provided URL http://twimlets.com/message to return the response.
> [AZURE.NOTE] While TwiML is designed for use by web services, you can view the TwiML in your browser. For example, click [twimlet_message_url](http://twimlets.com/message) to see an empty <Response> element; as another example, click [twimlet_message_url_hello_world](http://twimlets.com/message?Message%5B0%5D=Hello%20World) to see a <Response> element that contains a <Say> element.
Instead of relying on the Twilio-provided URL, you can create your own URL site that returns HTTP responses. You can create the site in any language that returns HTTP responses. This topic assumes you'll be hosting the URL from an Node.js generic handler.
The following script results in a TwiML response that says Hello World on the call.
var twilio = require('twilio');
exports.post = function(request, response) {
var twiml = new twilio.TwimlResponse();
twiml.say('ahoy hoy! Testing Twilio and node.js', {
voice: 'woman'
});
response.set('Content-Type', 'text/xml');
response.send(twiml.toString());
};
For more information about TwiML, see [https://www.twilio.com/docs/api/twiml][twiml].
Once you have set up a way to provide TwiML responses, you can pass that URL into the `client.calls.create` method as shown in the following code sample:
var twilio = require('twilio');
exports.post = function(request, response) {
var client = new twilio.RestClient('ACCOUNT_SID', 'AUTH_TOKEN');
client.calls.create({
to:'+16515556677',
from: '+14506667788',
url: 'http://.azure-mobile.net/api/makeCall'
}, function(err, responseData) {
console.log(responseData.from);
response.send('');
});
};
## How to: Use additional Twilio services
In addition to the examples shown here, Twilio offers web-based APIs that you can use to leverage additional Twilio functionality from your Azure application. For full details, see the [Twilio API documentation][twilio_api].
## Next steps
Now that you've learned the basics of the Twilio service, follow these links to learn more:
* [Twilio Security Guidelines] [twilio_security_guidelines]
* [Twilio HowTos and Example Code] [twilio_howtos]
* [Twilio Quickstart Tutorials][twilio_quickstarts]
* [Twilio on GitHub] [twilio_on_github]
* [Talk to Twilio Support] [twilio_support]
[twilio_security_guidelines]: http://www.twilio.com/docs/security
[twilio_howtos]: http://www.twilio.com/docs/howto
[twilio_on_github]: https://github.com/twilio
[twilio_support]: http://www.twilio.com/help/contact
[twilio_quickstarts]: http://www.twilio.com/docs/quickstart
[twilio_rest_making_calls]: http://www.twilio.com/docs/api/rest/making-calls
[twilio_pricing]: http://www.twilio.com/pricing
[special_offer]: http://ahoy.twilio.com/azure
[twiml]: http://www.twilio.com/docs/api/twiml
[twilio_api]: http://www.twilio.com/api
[try_twilio]: https://www.twilio.com/try-twilio
[twilio_console]: https://www.twilio.com/console
================================================
FILE: docs/partner-xamarin-mobile-services-android-get-started-push.md
================================================
# Add push notifications to your Mobile Services app
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-push.md)
- [(iOS | JavaScript)](mobile-services-javascript-backend-ios-get-started-push.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-push.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-get-started-push.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-javascript-backend-windows-phone-get-started-push.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started-push.md)
- [(Android | Javascript)](mobile-services-javascript-backend-android-get-started-push.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-push.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-push.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-push.md)
- [(Xamarin.Forms | JavaScript)](partner-xamarin-mobile-services-xamarin-forms-get-started-push.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
## Overview
This topic shows you how to use Azure Mobile Services to send push notifications to a Xamarin.Android app. In this tutorial you add push notifications using the Google Cloud Messaging (GCM) service to the [Get started with Mobile Services] project. When complete, your mobile service will send a push notification each time a record is inserted.
This tutorial requires the following:
+ An active Google account.
+ [Google Cloud Messaging Client Component]. You will add this component during the tutorial.
You should already have Xamarin and the [Azure Mobile Services Component] installed in your project from when you completed either [Get started with Mobile Services].
## Enable Google Cloud Messaging
1. Navigate to the [Google Cloud Console](https://console.developers.google.com/project), sign in with your Google account credentials.
2. Click **Create Project**, type a project name, then click **Create**. If requested, carry out the SMS Verification, and click **Create** again.

Type in your new **Project name** and click **Create project**.
3. Click the **Utilities and More** button and then click **Project Information**. Make a note of the **Project Number**. You will need to set this value as the `SenderId` variable in the client app.

4. In the project dashboard, under **Mobile APIs**, click **Google Cloud Messaging**, then on the next page click **Enable API** and accept the terms of service.


5. In the project dashboard, Click **Credentials** > **Create Credential** > **API Key**.

6. In **Create a new key**, click **Server key**, type a name for your key, then click **Create**.
7. Make a note of the **API KEY** value.
You will use this API key value to enable Azure to authenticate with GCM and send push notifications on behalf of your app.
## Configure your mobile service to send push requests
1. Log on to the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services**, and then click your app.
2. Click the **Push** tab, enter the **API Key** value obtained from GCM in the previous procedure, then click **Save**.

>[AZURE.NOTE]When you set your GCM credentials for enhanced push notifications in the Push tab in the portal, they are shared with Notification Hubs to configure the notification hub with your app.
Both your mobile service and your app are now configured to work with GCM and Notification Hubs.
## Update the registered insert script to send notifications
>[AZURE.TIP] The following steps show you how to update the script registered to the insert operation on the TodoItem table in the Azure classic portal. You can also access and edit this mobile service script directly in Visual Studio, in the Azure node of Server Explorer.
1. In the [Azure classic portal](https://manage.windowsazure.com/), click the **Data** tab and then click the **TodoItem** table.
2. In **todoitem**, click the **Script** tab and select **Insert**.
This displays the function that is invoked when an insert occurs in the **TodoItem** table.
3. Replace the insert function with the following code, and then click **Save**:
function insert(item, user, request) {
// Define a simple payload for a GCM notification.
var payload = {
"data": {
"message": item.text
}
};
request.execute({
success: function() {
// If the insert succeeds, send a notification.
push.gcm.send(null, payload, {
success: function(pushResponse) {
console.log("Sent push:", pushResponse, payload);
request.respond();
},
error: function (pushResponse) {
console.log("Error Sending push:", pushResponse);
request.respond(500, { error: pushResponse });
}
});
},
error: function(err) {
console.log("request.execute error", err)
request.respond();
}
});
}
This registers a new insert script, which uses the [gcm object](http://go.microsoft.com/fwlink/p/?LinkId=282645) to send a push notification to all registered devices after the insert succeeds.
## Configure the existing project for push notifications
1. In the Solution view (or **Solution Explorer** in Visual Studio), right-click the **Components** folder, click **Get More Components...**, search for the **Google Cloud Messaging Client** component and add it to the project.
2. Open the ToDoActivity.cs project file and add the following using statement to the class:
using Gcm.Client;
3. In the **ToDoActivity** class, add the following new code:
// Create a new instance field for this activity.
static ToDoActivity instance = new ToDoActivity();
// Return the current activity instance.
public static ToDoActivity CurrentActivity
{
get
{
return instance;
}
}
// Return the Mobile Services client.
public MobileServiceClient CurrentClient
{
get
{
return client;
}
}
This enables you to access the mobile client instance from the push handler service process.
4. Add the following code to the **OnCreate** method, after the **MobileServiceClient** is created:
// Set the current instance of TodoActivity.
instance = this;
// Make sure the GCM client is set up correctly.
GcmClient.CheckDevice(this);
GcmClient.CheckManifest(this);
// Register the app for push notifications.
GcmClient.Register(this, ToDoBroadcastReceiver.senderIDs);
Your **ToDoActivity** is now prepared for adding push notifications.
## Add push notifications code to your app
4. Create a new class in the project called `ToDoBroadcastReceiver`.
5. Add the following using statements to **ToDoBroadcastReceiver** class:
using Gcm.Client;
using Microsoft.WindowsAzure.MobileServices;
6. Add the following permission requests between the **using** statements and the **namespace** declaration:
[assembly: Permission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "com.google.android.c2dm.permission.RECEIVE")]
//GET_ACCOUNTS is only needed for android versions 4.0.3 and below
[assembly: UsesPermission(Name = "android.permission.GET_ACCOUNTS")]
[assembly: UsesPermission(Name = "android.permission.INTERNET")]
[assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
7. Replace the existing **ToDoBroadcastReceiver** class definition with the following:
[BroadcastReceiver(Permission = Gcm.Client.Constants.PERMISSION_GCM_INTENTS)]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_MESSAGE },
Categories = new string[] { "@PACKAGE_NAME@" })]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_REGISTRATION_CALLBACK },
Categories = new string[] { "@PACKAGE_NAME@" })]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_LIBRARY_RETRY },
Categories = new string[] { "@PACKAGE_NAME@" })]
public class ToDoBroadcastReceiver : GcmBroadcastReceiverBase
{
// Set the Google app ID.
public static string[] senderIDs = new string[] { "" };
}
In the above code, you must replace _``_ with the project number assigned by Google when you provisioned your app in the Google developer portal.
8. In the ToDoBroadcastReceiver.cs project file, add the following code that defines the **PushHandlerService** class:
// The ServiceAttribute must be applied to the class.
[Service]
public class PushHandlerService : GcmServiceBase
{
public static string RegistrationID { get; private set; }
public PushHandlerService() : base(ToDoBroadcastReceiver.senderIDs) { }
}
Note that this class derives from **GcmServiceBase** and that the **Service** attribute must be applied to this class.
>[AZURE.NOTE]The **GcmServiceBase** class implements the **OnRegistered()**, **OnUnRegistered()**, **OnMessage()** and **OnError()** methods. You must override these methods in the **PushHandlerService** class.
5. Add the following code to the **PushHandlerService** class that overrides the **OnRegistered** event handler.
protected override void OnRegistered(Context context, string registrationId)
{
System.Diagnostics.Debug.WriteLine("The device has been registered with GCM.", "Success!");
// Get the MobileServiceClient from the current activity instance.
MobileServiceClient client = ToDoActivity.CurrentActivity.CurrentClient;
var push = client.GetPush();
List tags = null;
//// (Optional) Uncomment to add tags to the registration.
//var tags = new List() { "myTag" }; // create tags if you want
try
{
// Make sure we run the registration on the same thread as the activity,
// to avoid threading errors.
ToDoActivity.CurrentActivity.RunOnUiThread(
async () => await push.RegisterNativeAsync(registrationId, tags));
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(
string.Format("Error with Azure push registration: {0}", ex.Message));
}
}
This method uses the returned GCM registration ID to register with Azure for push notifications.
10. Override the **OnMessage** method in **PushHandlerService** with the following code:
protected override void OnMessage(Context context, Intent intent)
{
string message = string.Empty;
// Extract the push notification message from the intent.
if (intent.Extras.ContainsKey("message"))
{
message = intent.Extras.Get("message").ToString();
var title = "New item added:";
// Create a notification manager to send the notification.
var notificationManager =
GetSystemService(Context.NotificationService) as NotificationManager;
// Create a new intent to show the notification in the UI.
PendingIntent contentIntent =
PendingIntent.GetActivity(context, 0,
new Intent(this, typeof(ToDoActivity)), 0);
// Create the notification using the builder.
var builder = new Notification.Builder(context);
builder.SetAutoCancel(true);
builder.SetContentTitle(title);
builder.SetContentText(message);
builder.SetSmallIcon(Resource.Drawable.ic_launcher);
builder.SetContentIntent(contentIntent);
var notification = builder.Build();
// Display the notification in the Notifications Area.
notificationManager.Notify(1, notification);
}
}
12. Override the **OnUnRegistered()** and **OnError()** methods with the following code.
protected override void OnUnRegistered(Context context, string registrationId)
{
throw new NotImplementedException();
}
protected override void OnError(Context context, string errorId)
{
System.Diagnostics.Debug.WriteLine(
string.Format("Error occurred in the notification: {0}.", errorId));
}
## Test push notifications in your app
You can test the app by directly attaching an Android phone with a USB cable, or by using a virtual device in the emulator.
4. Create a new class in the project called `ToDoBroadcastReceiver`.
5. Add the following using statements to **ToDoBroadcastReceiver** class:
using Gcm.Client;
using Microsoft.WindowsAzure.MobileServices;
6. Add the following permission requests between the **using** statements and the **namespace** declaration:
[assembly: Permission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "com.google.android.c2dm.permission.RECEIVE")]
//GET_ACCOUNTS is only needed for android versions 4.0.3 and below
[assembly: UsesPermission(Name = "android.permission.GET_ACCOUNTS")]
[assembly: UsesPermission(Name = "android.permission.INTERNET")]
[assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
7. Replace the existing **ToDoBroadcastReceiver** class definition with the following:
[BroadcastReceiver(Permission = Gcm.Client.Constants.PERMISSION_GCM_INTENTS)]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_MESSAGE },
Categories = new string[] { "@PACKAGE_NAME@" })]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_REGISTRATION_CALLBACK },
Categories = new string[] { "@PACKAGE_NAME@" })]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_LIBRARY_RETRY },
Categories = new string[] { "@PACKAGE_NAME@" })]
public class ToDoBroadcastReceiver : GcmBroadcastReceiverBase
{
// Set the Google app ID.
public static string[] senderIDs = new string[] { "" };
}
In the above code, you must replace _``_ with the project number assigned by Google when you provisioned your app in the Google developer portal.
8. In the ToDoBroadcastReceiver.cs project file, add the following code that defines the **PushHandlerService** class:
// The ServiceAttribute must be applied to the class.
[Service]
public class PushHandlerService : GcmServiceBase
{
public static string RegistrationID { get; private set; }
### Setting up the Android emulator for testing
When you run this app in the emulator, make sure that you use an Android Virtual Device (AVD) that supports Google APIs.
> [AZURE.IMPORTANT] In order to receive push notifications, you must set up a Google account on your Android Virtual Device (in the emulator, navigate to **Settings** and click **Add Account**). Also, make sure that the emulator is connected to the Internet.
1. From **Tools**, click **Open Android Emulator Manager**, select your device, and then click **Edit**.

2. Select **Google APIs** in **Target**, then click **OK**.

3. On the top toolbar, click **Run**, and then select your app. This starts the emulator and runs the app.
The app retrieves the *registrationId* from GCM and registers with the Notification Hub.
### Inserting a new item generates a notification.
1. In the app, type meaningful text, such as _A new Mobile Services task_ and then click the **Add** button.
2. Swipe down from the top of the screen to open the device's Notification Center to see the notification.

You have successfully completed this tutorial.
## Next steps
Learn more about Mobile Services and Notification Hubs in the following topics:
* [Get started with authentication](mobile-services-android-get-started-users.md)
Learn how to authenticate users of your app with different account types using mobile services.
* [What are Notification Hubs?](https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-push-notification-overview/)
Learn more about how Notification Hubs works to deliver notifications to your apps across all major client platforms.
* [Debug Notification Hubs applications](http://go.microsoft.com/fwlink/p/?linkid=386630)
Get guidance troubleshooting and debugging Notification Hubs solutions.
* [How to use the .NET client library for Mobile Services](mobile-services-dotnet-how-to-use-client-library.md)
Learn more about how to use Mobile Services with Xamarin C# code.
* [Mobile Services server script reference](mobile-services-how-to-use-server-scripts.md)
Learn more about how to implement business logic in your mobile service.
[Get started with Mobile Services]: mobile-services-ios-get-started.md
[Google Cloud Messaging Client Component]: http://components.xamarin.com/view/GCMClient/
[Azure Mobile Services Component]: http://components.xamarin.com/view/azure-mobile-services/
================================================
FILE: docs/partner-xamarin-mobile-services-android-get-started-users.md
================================================
# Add authentication to your Mobile Services app
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-users.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started-users.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-users.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-get-started-users.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-windows-phone-get-started-users.md)
- [(Android | Javascript)](mobile-services-android-get-started-users.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started-users.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-users.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-users.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-users.md)
- [(HTML | Javascript)](mobile-services-html-get-started-users.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This topic shows you how to authenticate users in Azure Mobile Services from your Xamarin.Android app. In this tutorial, you add authentication to the quickstart project using an identity provider that is supported by Mobile Services. After being successfully authenticated and authorized by Mobile Services, the user ID value is displayed.
This tutorial walks you through these basic steps to enable authentication in your app:
1. [Register your app for authentication and configure Mobile Services]
2. [Restrict table permissions to authenticated users]
3. [Add authentication to the app]
This tutorial is based on the Mobile Services quickstart. You must also first complete the tutorial [Get started with Mobile Services].
Completing this tutorial requires Visual Studio with Xamarin on Windows or Xamarin Studio on Mac OS X. Complete installation instructions are on [Setup and Install for Visual Studio and Xamarin](https://msdn.microsoft.com/library/mt613162.aspx).
## Register your app for authentication and configure Mobile Services
1. In the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Dashboard**, and make a note of the **Mobile Service URL** value.
2. Register your app with one or more of the following authentication providers:
* [Google](./
mobile-services-how-to-register-google-authentication.md)
* [Facebook](./
mobile-services-how-to-register-facebook-authentication.md)
* [Twitter](./
mobile-services-how-to-register-twitter-authentication.md)
* [Microsoft](./
mobile-services-how-to-register-microsoft-authentication.md)
* [Azure Active Directory](./
mobile-services-how-to-register-active-directory-authentication.md).
Make a note of the client identity and client secret values generated by the provider. Do not distribute or share the client secret.
3. Back in the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Identity** > your identity provider settings, then enter the client ID and secret value from your provider.
You've now configured both your app and your mobile service to work with your auth provider. You may optionally repeat all these steps for each additional identity provider you'd like to support.
> [AZURE.IMPORTANT] Verify that you've set the correct redirect URI on your identity provider's developer site. As described in the linked instructions for each provider above, the redirect URI may be different for a .NET backend service vs. for a JavaScript backend service. An incorrectly configured redirect URI may result in the login screen not being displayed properly and the app malfunctioning in unexpected ways.
## Restrict permissions to authenticated users
To secure your endpoints, you must restrict access to only authenticated clients.
1. In the [Azure classic portal](https://manage.windowsazure.com/), navigate to your mobile service, then click **Data** > your table name (**TodoItem**) > **Permissions**.
2. Set all of the table operation permissions to **Only authenticated users**.
This ensures that all operations against the table require an authenticated user, which is required for this tutorial. You can set different permissions on each operations to support your specific scenario.
3. In Xamarin Studio, open the project that you created when you completed the tutorial [Get started with Mobile Services].
4. From the **Run** menu, click **Start debugging** to start the app; verify that an unhandled exception with a status code of 401 (Unauthorized) is raised after the app starts.
This happens because the app attempts to access Mobile Services as an unauthenticated user, but the _TodoItem_ table now requires authentication.
Next, you will update the app to authenticate users before requesting resources from the mobile service.
## Add authentication to the app
1. Add the following property to the **ToDoActivity** class:
private MobileServiceUser user;
2. Add the following method to the **ToDoActivity** class:
private async Task Authenticate()
{
try
{
user = await client.LoginAsync(this, MobileServiceAuthenticationProvider.MicrosoftAccount);
CreateAndShowDialog(string.Format("you are now logged in - {0}", user.UserId), "Logged in!");
}
catch (Exception ex)
{
CreateAndShowDialog(ex, "Authentication failed");
}
}
This creates a new method to handle the authentication process. The user is authenticated by using a Microsoft Account login. A dialog is displayed which displays the ID of the authenticated user. You cannot proceed without a positive authentication.
> [AZURE.NOTE] If you are using an identity provider other than Microsoft, change the value passed to the **login** method above to one of the following: _Facebook_, _Google_, _Twitter_, or _WindowsAzureActiveDirectory_.
3. In the **OnCreate** method, add the following line of code after the code that instantiates the `MobileServiceClient` object.
await Authenticate();
This call starts the authentication process and awaits it asynchronously.
4. Move the remaining code after `await Authenticate();` in the **OnCreate** method to a new **CreateTable** method, which looks like this:
private async Task CreateTable()
{
await InitLocalStoreAsync();
// Get the Mobile Service Table instance to use
toDoTable = client.GetSyncTable();
textNewToDo = FindViewById(Resource.Id.textNewToDo);
// Create an adapter to bind the items with the view
adapter = new ToDoItemAdapter(this, Resource.Layout.Row_List_To_Do);
var listViewTodo = FindViewById(Resource.Id.listViewToDo);
listViewTodo.Adapter = adapter;
// Load the items from the Mobile Service
await RefreshItemsFromTableAsync();
}
5. Then call the new **CreateTable** method in **OnCreate** after the **Authenticate** call added in step 2:
await CreateTable();
6. From the **Run** menu, click **Start debugging** to start the app and sign in with your chosen identity provider.
When you are successfully logged-in, the app should run without errors, and you should be able to query Mobile Services and make updates to data.
## Get completed example
Download the [completed example project]. Be sure to update the **applicationURL** and **applicationKey** variables with your own Azure settings.
## Next steps
In the next tutorial, [Authorize users with scripts], you will take the user ID value provided by Mobile Services based on an authenticated user and use it to filter the data returned by Mobile Services.
[Register your app for authentication and configure Mobile Services]: #register
[Restrict table permissions to authenticated users]: #permissions
[Add authentication to the app]: #add-authentication
[Next Steps]:#next-steps
[4]: ./media/partner-xamarin-mobile-services-android-get-started-users/mobile-services-selection.png
[5]: ./media/partner-xamarin-mobile-services-android-get-started-users/mobile-service-uri.png
[13]: ./media/partner-xamarin-mobile-services-android-get-started-users/mobile-identity-tab.png
[14]: ./media/partner-xamarin-mobile-services-android-get-started-users/mobile-portal-data-tables.png
[15]: ./media/partner-xamarin-mobile-services-android-get-started-users/mobile-portal-change-table-perms.png
[Get started with Mobile Services]: partner-xamarin-mobile-services-android-get-started.md
[Authorize users with scripts]: mobile-services-javascript-backend-service-side-authorization.md
[completed example project]: http://go.microsoft.com/fwlink/p/?LinkId=331328
================================================
FILE: docs/partner-xamarin-mobile-services-android-get-started.md
================================================
# Get started with Mobile Services
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal JavaScript | Javascript)](mobile-services-javascript-backend-windows-store-javascript-get-started.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started.md)
- [(Android | Javascript)](mobile-services-android-get-started.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started.md)
- [(HTML | Javascript)](mobile-services-html-get-started.md)
- [(PhoneGap | Javascript)](mobile-services-javascript-backend-phonegap-get-started.md)
- [(Sencha | Javascript)](partner-sencha-mobile-services-get-started.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This tutorial shows you how to add a cloud-based backend service to a Xamarin.Android app using Azure Mobile Services. In this tutorial, you will create both a new mobile service and a simple *To do list* app that stores app data in the new mobile service.
If you prefer to watch a video, the clip below follows the same steps on this tutorial.
Video: "Getting Started with Xamarin and Azure Mobile Services" with Craig Dunn, developer evangelist for Xamarin (duration: 10:05 min)
> [AZURE.VIDEO getting-started-with-xamarin-and-mobile-services]
A screenshot from the completed app is below:
![][0]
Completing this tutorial requires XCode and Xamarin Studio for OS X or Visual Studio on Windows with a networked Mac. Complete installation instructions are on [Setup and Install for Visual Studio and Xamarin](https://msdn.microsoft.com/library/mt613162.aspx).
The downloaded quickstart project contains the Azure Mobile services component for Xamarin.Android. While this project targets Android 4.2 or a later version, the Mobile Services SDK requires only Android 2.2 or a later version.
> [AZURE.IMPORTANT] To complete this tutorial, you need an Azure account. If you don't have an account, you can sign up for an Azure trial and get up to 10 free mobile services that you can keep using even after your trial ends. For details, see [Azure Free Trial](https://azure.microsoft.com/pricing/free-trial/?WT.mc_id=A9C9624B5).
## Create a new mobile service
Follow these steps to create a new mobile service.
1. Log into the [Azure classic portal](https://manage.windowsazure.com/). At the bottom of the navigation pane, click **+NEW**. Expand **Compute** and **Mobile Service**, then click **Create**.

This displays the **Create a Mobile Service** dialog.
2. In the **Create a Mobile Service** dialog, select **Create a free 20 MB SQL Database**, select **JavaScript** runtime, then type a subdomain name for the new mobile service in the **URL** textbox. Click the right arrow button to go to the next page.

This displays the **Specify database settings** page.
>[AZURE.NOTE]As part of this tutorial, you create a new SQL Database instance and server. You can reuse this new database and administer it as you would any other SQL Database instance. If you already have a database in the same region as the new mobile service, you can instead choose **Use existing Database** and then select that database. The use of a database in a different region is not recommended because of additional bandwidth costs and higher latencies.
3. In **Name**, type the name of the new database, then type **Login name**, which is the administrator login name for the new SQL Database server, type and confirm the password, and click the check button to complete the process.

You have now created a new mobile service that can be used by your mobile apps.
## Create a new Xamarin.Android app
Once you have created your mobile service, you can follow an easy quickstart in the Azure classic portal to either create a new app or modify an existing app to connect to your mobile service.
In this section you will create a new Xamarin.Android app that is connected to your mobile service.
1. In the [Azure classic portal], click **Mobile Services**, and then click the mobile service that you just created.
2. In the quickstart tab, click **Xamarin.Android** under **Choose platform** and expand **Create a new Android app**.
![][6]
This displays the three easy steps to create a Xamarin.Android app connected to your mobile service.
![][7]
3. Click **Create TodoItem table** to create a table to store app data.
4. Under **Download and run app**, click **Download**.
This downloads the project for the sample _To do list_ application that is connected to your mobile service. Save the compressed project file to your local computer, and make a note of where you save it.
## Run your Android app
The final stage of this tutorial is to build and run your new app.
1. Browse to the location where you saved the compressed project files and expand the files on your computer.
2. In Xamarin Studio or Visual Studio, click **File** then **Open**, navigate to the uncompressed sample files, and select **XamarinTodoQuickStart.Android.sln** to open it.
3. Press the **Run** button to build the project and start the app. You will be asked to select an emulator or a connected USB device.
> [AZURE.NOTE] To be able to run the project in the Android emulator, you must define at least one Android Virtual Device (AVD). Use the AVD Manager to create and manage these devices.
4. In the app, type meaningful text, such as _Complete the tutorial_, and then click **Add**.
![][10]
This sends a POST request to the new mobile service hosted in Azure. Data from the request is inserted into the TodoItem table. Items stored in the table are returned by the mobile service, and the data is displayed in the list.
> [AZURE.NOTE]
> You can review the code that accesses your mobile service to query and insert data, which is found in the ToDoActivity.cs C# file.
6. Back in the [Azure classic portal], click the **Data** tab and then click the **TodoItems** table.
![][11]
This lets you browse the data inserted by the app into the table.
![][12]
## Next Steps
Now that you have completed the quickstart, learn how to perform additional important tasks in Mobile Services:
* [Get started with offline data sync]
Learn how the quickstart uses offline data sync to make the app responsive and robust.
* [Get started with authentication]
Learn how to authenticate users of your app with an identity provider.
* [Get started with push notifications]
Learn how to send a very basic push notification to your app.
[Getting started with Mobile Services]:#getting-started
[Create a new mobile service]:#create-new-service
[Define the mobile service instance]:#define-mobile-service-instance
[Next Steps]:#next-steps
[0]: ./media/partner-xamarin-mobile-services-android-get-started/mobile-quickstart-completed-android.png
[2]: ./media/partner-xamarin-mobile-services-android-get-started/mobile-create.png
[3]: ./media/partner-xamarin-mobile-services-android-get-started/mobile-create-page1.png
[4]: ./media/partner-xamarin-mobile-services-android-get-started/mobile-create-page2.png
[5]: ./media/partner-xamarin-mobile-services-android-get-started/obile-services-selection.png
[6]: ./media/partner-xamarin-mobile-services-android-get-started/mobile-portal-quickstart-xamarin-android.png
[7]: ./media/partner-xamarin-mobile-services-android-get-started/mobile-quickstart-steps-xamarin-android.png
[8]: ./media/partner-xamarin-mobile-services-android-get-started/mobile-xamarin-project-android-xs.png
[9]: ./media/partner-xamarin-mobile-services-android-get-started/mobile-xamarin-project-android-vs.png
[10]: ./media/partner-xamarin-mobile-services-android-get-started/mobile-quickstart-startup-android.png
[11]: ./media/partner-xamarin-mobile-services-android-get-started/mobile-data-tab.png
[12]: ./media/partner-xamarin-mobile-services-android-get-started/mobile-data-browse.png
[13]: ./media/partner-xamarin-mobile-services-android-get-started/mobile-services-diagram.png
[Get started with data]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-data-xamarin-android
[Get started with offline data sync]: mobile-services-xamarin-android-get-started-offline-data.md
[Get started with authentication]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-users-xamarin-android
[Get started with push notifications]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-push-xamarin-android
[Mobile Services Android SDK]: https://go.microsoft.com/fwLink/p/?LinkID=266533
[Azure]: http://azure.microsoft.com/
[Azure classic portal]: https://manage.windowsazure.com/
================================================
FILE: docs/partner-xamarin-mobile-services-ios-get-started-push.md
================================================
# Add push notifications to your Mobile Services app
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-push.md)
- [(iOS | JavaScript)](mobile-services-javascript-backend-ios-get-started-push.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-push.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-get-started-push.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-javascript-backend-windows-phone-get-started-push.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started-push.md)
- [(Android | Javascript)](mobile-services-javascript-backend-android-get-started-push.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-push.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-push.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-push.md)
- [(Xamarin.Forms | JavaScript)](partner-xamarin-mobile-services-xamarin-forms-get-started-push.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
## Overview
This topic shows you how to use Azure Mobile Services to send push notifications to a Xamarin.iOS 8 app. In this tutorial you add push notifications using the Apple Push Notification service (APNS) to the [Get started with Mobile Services] project. When complete, your mobile service will send a push notification each time a record is inserted.
This tutorial requires the following:
+ An iOS 8 device (you cannot test push notifications in the iOS Simulator)
+ iOS Developer Program membership
+ [Xamarin Studio]
+ [Azure Mobile Services Component]
>[AZURE.IMPORTANT] Because of APNS requirements, you must deploy and test push notifications on an iOS capable device (iPhone or iPad) instead of in the emulator.
APNS uses certificates to authenticate your mobile service. Follow these instructions to create the necessary certificates and upload it to your Mobile Service. For the official APNS feature documentation, see [Apple Push Notification Service].
## Generate the Certificate Signing Request file
First you must generate the Certificate Signing Request (CSR) file, which is used by Apple to generate a signed certificate.
1. From Utilities, run the **Keychain Access tool**.
2. Click **Keychain Access**, expand **Certificate Assistant**, then click **Request a Certificate from a Certificate Authority...**.
![][5]
3. Enter your **User Email Address**, type in a **Common Name** value, make sure that **Saved to disk** is selected, and then click **Continue**.
![][6]
4. Type a name for the Certificate Signing Request (CSR) file in **Save As**, select the location in **Where**, then click **Save**.
![][7]
Remember the location you chose.
Next, you will register your app with Apple, enable push notifications, and upload this exported CSR to create a push certificate.
## Register your app for push notifications
To be able to send push notifications to an iOS app from mobile services, you must register your application with Apple and register for push notifications.
1. If you have not already registered your app, navigate to the iOS Provisioning Portal at the Apple Developer Center, log on with your Apple ID, click **Identifiers**, then click **App IDs**, and finally click on the **+** sign to create an app ID for your app.
![][102]
2. Type a name for your app in **Description**, enter and remember the unique **Bundle Identifier**, check the "Push Notifications" option in the "App Services" section, and then click **Continue**. This example uses the ID **MobileServices.Quickstart** but you may not reuse this same ID, as app IDs must be unique across all users. As such, it is recommended that you append your full name or initials after the app name.
![][103]
This generates your app ID and requests you to **Submit** the information. Click **Submit**.
![][104]
Once you click **Submit**, you will see the **Registration complete** screen, as shown below. Click **Done**.
![][105]
3. Locate the app ID that you just created, and click on its row.
![][106]
Clicking on the app ID will display details on the app and app ID. Click the **Settings** button.
![][107]
4. Scroll to the bottom of the screen, and click the **Create Certificate...** button under the section **Development Push SSL Certificate**.
![][108]
This displays the "Add iOS Certificate" assistant.
Note: This tutorial uses a development certificate. The same process is used when registering a production certificate. Just make sure that you set the same certificate type when you upload the certificate to Mobile Services.
5. Click **Choose File**, browse to the location where you saved the CSR file earlier, then click **Generate**.
![][110]
6. After the certificate is created by the portal, click the **Download** button, and click **Done**.
![][111]
This downloads the signing certificate and saves it to your computer in your Downloads folder.
![][9]
Note: By default, the downloaded file a development certificate is named aps_development.cer.
7. Double-click the downloaded push certificate **aps_development.cer**.
This installs the new certificate in the Keychain, as shown below:
![][10]
Note: The name in your certificate might be different, but it will be prefixed with Apple Development iOS Push Notification Services:.
Later, you will use this certificate to generate a .p12 file and upload it to Mobile Services to enable authentication with APNS.
## Create a provisioning profile for the app
1. Back in the iOS Provisioning Portal, select **Provisioning Profiles**, select **All**, and then click the **+** button to create a new profile. This launches the **Add iOS Provisiong Profile** Wizard.
![][112]
2. Select **iOS App Development** under **Development** as the provisiong profile type, and click **Continue**.
3. Next, select the app ID for the Mobile Services Quickstart app from the **App ID** drop-down list, and click **Continue**.
![][113]
4. In the **Select certificates** screen, select the certificate created earlier, and click **Continue**.
![][114]
5. Next, select the **Devices** to use for testing, and click **Continue**.
![][115]
6. Finally, pick a name for the profile in **Profile Name**, click **Generate**, and click **Done**.
![][116]
This creates a new provisioning profile.
![][117]
## Configure Mobile Services to send push requests
After you have registered your app with APNS and configured your project, you must next configure your mobile service to integrate with APNS.
1. In Keychain Access, right-click the new certificate, click **Export**, name your file, select the **.p12** format, then click **Save**.
![][28]
Make a note of the file name and location of the exported certificate.
2. Log on to the [Azure classic portal], click **Mobile Services**, and then click your app.
![][18]
3. Click the **Push** tab and click **Upload** under **apple push notification settings**.
![][19]
This displays the Upload Certificate dialog.
4. Click **File**, select the exported certificate .p12 file, enter the **Password**, make sure that the correct **Mode** is selected, click the check icon, then click **Save**.
![][20]
Your mobile service is now configured to work with APNS.
## Configure your Xamarin.iOS application
1. In Xamarin.Studio, open **Info.plist**, and update the **Bundle Identifier** with the ID you created earlier.
![][121]
2. Scroll down to **Background Modes** and check the **Enable Background Modes** box and the **Remote notifications** box.
![][122]
3. Double click your project in the Solution Panel to open **Project Options**.
4. Choose **iOS Bundle Signing** under **Build**, and select the corresponding **Identity** and **Provisioning profile** you had just set up for this project.
![][120]
This ensures that the Xamarin project uses the new profile for code signing. For the official Xamarin device provisioning documentation, see [Xamarin Device Provisioning].
## Add push notifications to your app
1. In Xamarin.Studio, open the AppDelegate.cs file and add the following property:
public string DeviceToken { get; set; }
2. Open the **TodoItem** class and add the following property:
[JsonProperty(PropertyName = "deviceToken")]
public string DeviceToken { get; set; }
3. In **QSTodoService**, override the existing client declaration to be:
public MobileServiceClient client { get; private set; }
4. Then add the following method so **AppDelegate** can acquire the client later to register push notifications:
public MobileServiceClient GetClient {
get{
return client;
}
}
5. In **AppDelegate**, override the **FinishedLaunching** event:
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
// registers for push for iOS8
var settings = UIUserNotificationSettings.GetSettingsForTypes(
UIUserNotificationType.Alert
| UIUserNotificationType.Badge
| UIUserNotificationType.Sound,
new NSSet());
UIApplication.SharedApplication.RegisterUserNotificationSettings(settings);
UIApplication.SharedApplication.RegisterForRemoteNotifications();
return true;
}
6. In **AppDelegate**, override the **RegisteredForRemoteNotifications** event:
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
// Modify device token
DeviceToken = deviceToken.Description;
DeviceToken = DeviceToken.Trim ('<', '>').Replace (" ", "");
// Get Mobile Services client
MobileServiceClient client = QSTodoService.DefaultService.GetClient;
// Register for push with Mobile Services
IEnumerable tag = new List() { "uniqueTag" };
var push = client.GetPush ();
push.RegisterNativeAsync (DeviceToken, tag);
}
7. In **AppDelegate**, override the **ReceivedRemoteNotification** event:
public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
{
Debug.WriteLine(userInfo.ToString());
NSObject inAppMessage;
bool success = userInfo.TryGetValue(new NSString("inAppMessage"), out inAppMessage);
if (success)
{
var alert = new UIAlertView("Got push notification", inAppMessage.ToString(), null, "OK", null);
alert.Show();
}
}
8. In **QSTodoListViewController**, modify the **OnAdd** action to get the device token stored in **AppDelegeate**, and store it into the **TodoItem** being added.
string deviceToken = ((AppDelegate)UIApplication.SharedApplication.Delegate).DeviceToken;
var newItem = new TodoItem()
{
Text = itemText.Text,
Complete = false,
DeviceToken = deviceToken
};
Your app is now updated to support push notifications.
## Update the registered insert script in the Azure classic portal
1. In the [Azure classic portal], click the **Data** tab and then click the **TodoItem** table.
![][21]
2. In **todoitem**, click the **Script** tab and select **Insert**.
![][22]
This displays the function that is invoked when an insert occurs in the **TodoItem** table.
3. Replace the insert function with the following code, and then click **Save**:
function insert(item, user, request) {
request.execute();
// Set timeout to delay the notification, to provide time for the
// app to be closed on the device to demonstrate toast notifications
setTimeout(function() {
push.apns.send("uniqueTag", {
alert: "Toast: " + item.text,
payload: {
inAppMessage: "Hey, a new item arrived: '" + item.text + "'"
}
});
}, 2500);
}
This registers a new insert script, which uses the [apns object] to send a push notification (the inserted text) to the device provided in the insert request.
>[AZURE.NOTE] This script delays sending the notification to give you time to close the app to receive a toast notification.
## Test push notifications in your app
1. Press the **Run** button to build the project and start the app in an iOS capable device, then click **OK** to accept push notifications
![][23]
>[AZURE.NOTE] You must explicitly accept push notifications from your app. This request only occurs the first time that the app runs.
2. In the app, type meaningful text, such as _A new Mobile Services task_ and then click the plus (**+**) icon.
![][24]
3. Verify that a notification is received, then click **OK** to dismiss the notification.
![][25]
4. Repeat step 2 and immediately close the app, then verify that the following toast is shown.
![][26]
You have successfully completed this tutorial.
[Generate the certificate signing request]: #certificates
[Register your app and enable push notifications]: #register
[Create a provisioning profile for the app]: #profile
[Configure Mobile Services]: #configure-mobileServices
[Configure the Xamarin.iOS App]: #configure-app
[Update scripts to send push notifications]: #update-scripts
[Add push notifications to the app]: #add-push
[Insert data to receive notifications]: #test
[5]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-step5.png
[6]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-step6.png
[7]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-step7.png
[9]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-step9.png
[10]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-step10.png
[17]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-step17.png
[18]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-selection.png
[19]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-push-tab-ios.png
[20]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-push-tab-ios-upload.png
[21]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-portal-data-tables.png
[22]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-insert-script-push2.png
[23]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-quickstart-push1-ios.png
[24]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-quickstart-push2-ios.png
[25]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-quickstart-push3-ios.png
[26]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-quickstart-push4-ios.png
[28]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-step18.png
[101]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-01.png
[102]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-02.png
[103]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-03.png
[104]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-04.png
[105]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-05.png
[106]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-06.png
[107]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-07.png
[108]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-08.png
[110]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-10.png
[111]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-11.png
[112]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-12.png
[113]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-13.png
[114]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-14.png
[115]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-15.png
[116]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-16.png
[117]: ./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-17.png
[120]:./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-20.png
[121]:./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-21.png
[122]:./media/partner-xamarin-mobile-services-ios-get-started-push/mobile-services-ios-push-22.png
[Install Xcode]: https://go.microsoft.com/fwLink/p/?LinkID=266532
[iOS Provisioning Portal]: http://go.microsoft.com/fwlink/p/?LinkId=272456
[Mobile Services iOS SDK]: https://go.microsoft.com/fwLink/p/?LinkID=266533
[Apple Push Notification Service]: http://go.microsoft.com/fwlink/p/?LinkId=272584
[Get started with Mobile Services]: mobile-services-ios-get-started.md
[Xamarin Device Provisioning]: http://developer.xamarin.com/guides/ios/getting_started/installation/device_provisioning/
[Azure classic portal]: https://manage.windowsazure.com/
[apns object]: http://go.microsoft.com/fwlink/p/?LinkId=272333
[Azure Mobile Services Component]: http://components.xamarin.com/view/azure-mobile-services/
[completed example project]: http://go.microsoft.com/fwlink/p/?LinkId=331303
[Xamarin Studio]: http://xamarin.com/download
================================================
FILE: docs/partner-xamarin-mobile-services-ios-get-started-users.md
================================================
# Add authentication to your Mobile Services app
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-users.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started-users.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-users.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-get-started-users.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-windows-phone-get-started-users.md)
- [(Android | Javascript)](mobile-services-android-get-started-users.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started-users.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-users.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-users.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-users.md)
- [(HTML | Javascript)](mobile-services-html-get-started-users.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This topic shows you how to authenticate users in Azure Mobile Services from your app. In this tutorial, you add authentication to the quickstart project using an identity provider that is supported by Mobile Services. After being successfully authenticated and authorized by Mobile Services, the user ID value is displayed.
This tutorial walks you through these basic steps to enable authentication in your app:
1. [Register your app for authentication and configure Mobile Services]
2. [Restrict table permissions to authenticated users]
3. [Add authentication to the app]
This tutorial is based on the Mobile Services quickstart. You must also first complete the tutorial [Get started with Mobile Services].
Completing this tutorial requires [Xamarin Studio], XCode 6.0, and iOS 7.0 or later versions.
## Register your app for authentication and configure Mobile Services
1. In the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Dashboard**, and make a note of the **Mobile Service URL** value.
2. Register your app with one or more of the following authentication providers:
* [Google](./
mobile-services-how-to-register-google-authentication.md)
* [Facebook](./
mobile-services-how-to-register-facebook-authentication.md)
* [Twitter](./
mobile-services-how-to-register-twitter-authentication.md)
* [Microsoft](./
mobile-services-how-to-register-microsoft-authentication.md)
* [Azure Active Directory](./
mobile-services-how-to-register-active-directory-authentication.md).
Make a note of the client identity and client secret values generated by the provider. Do not distribute or share the client secret.
3. Back in the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services** > your mobile service > **Identity** > your identity provider settings, then enter the client ID and secret value from your provider.
You've now configured both your app and your mobile service to work with your auth provider. You may optionally repeat all these steps for each additional identity provider you'd like to support.
> [AZURE.IMPORTANT] Verify that you've set the correct redirect URI on your identity provider's developer site. As described in the linked instructions for each provider above, the redirect URI may be different for a .NET backend service vs. for a JavaScript backend service. An incorrectly configured redirect URI may result in the login screen not being displayed properly and the app malfunctioning in unexpected ways.
## Restrict permissions to authenticated users
To secure your endpoints, you must restrict access to only authenticated clients.
1. In the [Azure classic portal](https://manage.windowsazure.com/), navigate to your mobile service, then click **Data** > your table name (**TodoItem**) > **Permissions**.
2. Set all of the table operation permissions to **Only authenticated users**.
This ensures that all operations against the table require an authenticated user, which is required for this tutorial. You can set different permissions on each operations to support your specific scenario.
3. In Xcode, open the project that you created when you completed the tutorial [Get started with Mobile Services].
4. Press the **Run** button to build the project and start the app in the iPhone emulator; verify that an unhandled exception with a status code of 401 (Unauthorized) is raised after the app starts.
This happens because the app attempts to access Mobile Services as an unauthenticated user, but the _TodoItem_ table now requires authentication.
Next, you will update the app to authenticate users before requesting resources from the mobile service.
## Add authentication to the app
1. Open the **QSToDoService** project file and add the following variables
// Mobile Service logged in user
private MobileServiceUser user;
public MobileServiceUser User { get { return user; } }
2. Then add a new method named **Authenticate** to **ToDoService** defined as:
private async Task Authenticate(MonoTouch.UIKit.UIViewController view)
{
try
{
user = await client.LoginAsync(view, MobileServiceAuthenticationProvider.MicrosoftAccount);
}
catch (Exception ex)
{
Console.Error.WriteLine (@"ERROR - AUTHENTICATION FAILED {0}", ex.Message);
}
}
> [AZURE.NOTE] If you are using an identity provider other than a Microsoft Account, change the value passed to **LoginAsync** above to one of the following: _Facebook_, _Twitter_, _Google_, or _WindowsAzureActiveDirectory_.
3. Move the request for the **ToDoItem** table from the **ToDoService** constructor into a new method named **CreateTable**:
private async Task CreateTable()
{
// Create an MSTable instance to allow us to work with the ToDoItem table
todoTable = client.GetSyncTable();
}
4. Create a new asynchronous public method named **LoginAndGetData** defined as:
public async Task LoginAndGetData(MonoTouch.UIKit.UIViewController view)
{
await Authenticate(view);
await CreateTable();
}
5. In the **TodoListViewController** override the **ViewDidAppear** method and define it as found below. This logs in the user if the **ToDoService** doesn't yet have a handle on the user:
public override async void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
if (QSTodoService.DefaultService.User == null)
{
await QSTodoService.DefaultService.LoginAndGetData(this);
}
if (QSTodoService.DefaultService.User == null)
{
// TODO:: show error
return;
}
await RefreshAsync();
}
6. Remove the original call to **RefreshAsync** from **TodoListViewController.ViewDidLoad**.
7. Press the **Run** button to build the project, start the app in the iPhone emulator, then log-on with your chosen identity provider.
When you are successfully logged-in, the app should run without errors, and you should be able to query Mobile Services and make updates to data.
## Get completed example
Download the [completed example project]. Be sure to update the **applicationURL** and **applicationKey** variables with your own Azure settings.
## Next steps
In the next tutorial, [Authorize users with scripts], you will take the user ID value provided by Mobile Services based on an authenticated user and use it to filter the data returned by Mobile Services.
[Register your app for authentication and configure Mobile Services]: #register
[Restrict table permissions to authenticated users]: #permissions
[Add authentication to the app]: #add-authentication
[Next Steps]:#next-steps
[4]: ./media/partner-xamarin-mobile-services-ios-get-started-users/mobile-services-selection.png
[5]: ./media/partner-xamarin-mobile-services-ios-get-started-users/mobile-service-uri.png
[13]: ./media/partner-xamarin-mobile-services-ios-get-started-users/mobile-identity-tab.png
[14]: ./media/partner-xamarin-mobile-services-ios-get-started-users/mobile-portal-data-tables.png
[15]: ./media/partner-xamarin-mobile-services-ios-get-started-users/mobile-portal-change-table-perms.png
[Submit an app page]: http://go.microsoft.com/fwlink/p/?LinkID=266582
[My Applications]: http://go.microsoft.com/fwlink/p/?LinkId=262039
[Live SDK for Windows]: http://go.microsoft.com/fwlink/p/?LinkId=262253
[Get started with Mobile Services]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-xamarin-ios
[Get started with data]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-data-xamarin-ios
[Get started with authentication]: https://azure.microsoft.com/develop/mobile/tutorials/get-started-with-users-xamarin-ios
[Get started with push notifications]: https://azure.microsoft.com/develop/mobile/tutorials/-get-started-with-push-xamarin-ios
[Authorize users with scripts]: https://azure.microsoft.com/develop/mobile/tutorials/authorize-users-in-scripts-xamarin-ios
[completed example project]: http://go.microsoft.com/fwlink/p/?LinkId=331328
[Xamarin Studio]: http://xamarin.com/download
================================================
FILE: docs/partner-xamarin-mobile-services-ios-get-started.md
================================================
# Get started with Mobile Services
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started.md)
- [(iOS | JavaScript)](mobile-services-ios-get-started.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-store-dotnet-get-started.md)
- [(Windows Runtime 8.1 universal JavaScript | Javascript)](mobile-services-javascript-backend-windows-store-javascript-get-started.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started.md)
- [(Android | Javascript)](mobile-services-android-get-started.md)
- [(Xamarin.iOS | .NET)](mobile-services-dotnet-backend-xamarin-ios-get-started.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started.md)
- [(HTML | Javascript)](mobile-services-html-get-started.md)
- [(PhoneGap | Javascript)](mobile-services-javascript-backend-phonegap-get-started.md)
- [(Sencha | Javascript)](partner-sencha-mobile-services-get-started.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This tutorial shows you how to add a cloud-based backend service to a Xamarin.iOS app using Azure Mobile Services. In this tutorial, you will create both a new mobile service and a simple *To do list* app that stores app data in the new mobile service.
If you prefer to watch a video, the clip below follows the same steps as this tutorial.
Video: "Getting Started with Xamarin and Azure Mobile Services" with Craig Dunn, developer evangelist for Xamarin (duration: 10:05 min)
> [AZURE.VIDEO getting-started-with-xamarin-and-mobile-services]
A screenshot from the completed app is below:
![][0]
Completing this tutorial requires XCode and Xamarin Studio for OS X or Visual Studio on Windows with a networked Mac. Complete installation instructions are on [Setup and Install for Visual Studio and Xamarin](https://msdn.microsoft.com/library/mt613162.aspx).
> [AZURE.IMPORTANT] To complete this tutorial, you need an Azure account. If you don't have an account, you can sign up for an Azure trial and get up to 10 free mobile services that you can keep using even after your trial ends. For details, see [Azure Free Trial](https://azure.microsoft.com/pricing/free-trial/).
## Create a new mobile service
Follow these steps to create a new mobile service.
1. Log into the [Azure classic portal](https://manage.windowsazure.com/). At the bottom of the navigation pane, click **+NEW**. Expand **Compute** and **Mobile Service**, then click **Create**.

This displays the **Create a Mobile Service** dialog.
2. In the **Create a Mobile Service** dialog, select **Create a free 20 MB SQL Database**, select **JavaScript** runtime, then type a subdomain name for the new mobile service in the **URL** textbox. Click the right arrow button to go to the next page.

This displays the **Specify database settings** page.
>[AZURE.NOTE]As part of this tutorial, you create a new SQL Database instance and server. You can reuse this new database and administer it as you would any other SQL Database instance. If you already have a database in the same region as the new mobile service, you can instead choose **Use existing Database** and then select that database. The use of a database in a different region is not recommended because of additional bandwidth costs and higher latencies.
3. In **Name**, type the name of the new database, then type **Login name**, which is the administrator login name for the new SQL Database server, type and confirm the password, and click the check button to complete the process.

You have now created a new mobile service that can be used by your mobile apps.
## Create a new Xamarin.iOS app
Once you have created your mobile service, you can follow an easy quickstart in the Azure classic portal to either create a new app or modify an existing app to connect to your mobile service.
In this section you will create a new Xamarin.iOS app that is connected to your mobile service.
1. In the [Azure classic portal], click **Mobile Services**, and then click the mobile service that you just created.
2. In the quickstart tab, click **Xamarin.iOS** under **Choose platform** and expand **Create a new Xamarin.iOS app**.
![][6]
This displays the three easy steps to create a Xamarin.iOS app connected to your mobile service.
![][7]
3. If you haven't already done so, download and install Xcode (we recommend the latest version, Xcode 6.0, or newer) and [Xamarin Studio].
4. Click **Create TodoItems table** to create a table to store app data.
5. Under **Download and run app**, click **Download**.
This downloads the project for the sample _To do list_ application that is connected to your mobile service and references the Azure Mobile Services component for Xamarin.iOS. Save the compressed project file to your local computer, and make a note of where you saved it.
## Run your new Xamarin.iOS app
The final stage of this tutorial is to build and run your new app.
1. Browse to the location where you saved the compressed project files, expand the files on your computer, and open the **XamarinTodoQuickStart.iOS.sln** solution file using Xamarin Studio or Visual Studio.
![][8]
![][9]
2. Press the **Run** button to build the project and start the app in the iPhone emulator, which is the default for this project.
3. In the app, type meaningful text, such as _Complete the tutorial_ and then click the plus (**+**) icon.
![][10]
This sends a POST request to the new mobile service hosted in Azure. Data from the request is inserted into the TodoItem table. Items stored in the table are returned by the mobile service, and the data is displayed in the list.
> [AZURE.NOTE] You can review the code that accesses your mobile service to query and insert data, which is found in the TodoService.cs C# file.
4. Back in the [Azure classic portal], click the **Data** tab and then click the **TodoItems** table.
![][11]
This lets you browse the data inserted by the app into the table.
![][12]
## Next Steps
Now that you have completed the quickstart, learn how to perform additional important tasks in Mobile Services:
* [Get started with offline data sync]
Learn how the quickstart uses offline data sync to make the app responsive and robust.
* [Get started with authentication]
Learn how to authenticate users of your app with an identity provider.
* [Get started with push notifications]
Learn how to send a very basic push notification to your app.
[Getting started with Mobile Services]:#getting-started
[Create a new mobile service]:#create-new-service
[Define the mobile service instance]:#define-mobile-service-instance
[Next Steps]:#next-steps
[0]: ./media/partner-xamarin-mobile-services-ios-get-started/mobile-quickstart-completed-ios.png
[6]: ./media/partner-xamarin-mobile-services-ios-get-started/mobile-portal-quickstart-xamarin-ios.png
[7]: ./media/partner-xamarin-mobile-services-ios-get-started/mobile-quickstart-steps-xamarin-ios.png
[8]: ./media/partner-xamarin-mobile-services-ios-get-started/mobile-xamarin-project-ios-xs.png
[9]: ./media/partner-xamarin-mobile-services-ios-get-started/mobile-xamarin-project-ios-vs.png
[10]: ./media/partner-xamarin-mobile-services-ios-get-started/mobile-quickstart-startup-ios.png
[11]: ./media/partner-xamarin-mobile-services-ios-get-started/mobile-data-tab.png
[12]: ./media/partner-xamarin-mobile-services-ios-get-started/mobile-data-browse.png
[Get started with offline data sync]: mobile-services-xamarin-ios-get-started-offline-data.md
[Get started with authentication]: partner-xamarin-mobile-services-ios-get-started-users.md
[Get started with push notifications]: partner-xamarin-mobile-services-ios-get-started-push.md
[Xamarin Studio]: http://xamarin.com/download
[Mobile Services iOS SDK]: https://go.microsoft.com/fwLink/p/?LinkID=266533
[Azure classic portal]: https://manage.windowsazure.com/
================================================
FILE: docs/partner-xamarin-mobile-services-xamarin-forms-get-started-push.md
================================================
# Add push notifications to your Xamarin.Forms app
> [AZURE.SELECTOR-LIST (Platform | Backend )]
- [(iOS | .NET)](mobile-services-dotnet-backend-ios-get-started-push.md)
- [(iOS | JavaScript)](mobile-services-javascript-backend-ios-get-started-push.md)
- [(Windows Runtime 8.1 universal C# | .NET)](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-push.md)
- [(Windows Runtime 8.1 universal C# | Javascript)](mobile-services-javascript-backend-windows-universal-dotnet-get-started-push.md)
- [(Windows Phone Silverlight 8.x | Javascript)](mobile-services-javascript-backend-windows-phone-get-started-push.md)
- [(Android | .NET)](mobile-services-dotnet-backend-android-get-started-push.md)
- [(Android | Javascript)](mobile-services-javascript-backend-android-get-started-push.md)
- [(Xamarin.iOS | Javascript)](partner-xamarin-mobile-services-ios-get-started-push.md)
- [(Xamarin.Android | Javascript)](partner-xamarin-mobile-services-android-get-started-push.md)
- [(Xamarin.Android | .NET)](mobile-services-dotnet-backend-xamarin-android-get-started-push.md)
- [(Xamarin.Forms | JavaScript)](partner-xamarin-mobile-services-xamarin-forms-get-started-push.md)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
## Overview
This tutorial shows you how to use Azure Mobile Services to send push notifications to the iOS, Android, and Windows Phone app of your Xamarin.Forms solution. Start by creating a mobile service. Then, you'll download a starter sample, register with the appropriate push notification services, and add code to the solution to receive notifications from those services.
When you complete this tutorial, your mobile service will send a push notification each time a user adds a task in one of the apps. You can find the completed sample here: [Completed Xamarin.Forms Azure Push Notification Sample].
This tutorial requires the following:
+ An iOS 8 device (you cannot test push notifications in the iOS Simulator)
+ iOS Developer Program membership
+ [Xamarin Studio]
+ [Azure Mobile Services Component]
+ An active Google account
+ [Google Cloud Messaging Client Component]. You will add this component during the tutorial.
In this topic:
1. [Create a New Mobile Service](#create-service)
2. [Download and Configure the Starter Sample](#download-starter-sample)
4. [Add push notifications to your Xamarin.Forms.iOS app](#iOS)
5. [Add push notifications to your Xamarin.Forms.Android app](#Android)
6. [Add push notifications to your Xamarin.Forms.Windows app](#Windows)
7. [Update Azure table insert script to send push notifications to all apps](#all-apps)
## Create a New Mobile Service
Next, you will create a new mobile service to replace the in-memory list for data storage. Follow these steps to create a new mobile service.
1. Log into the [Azure classic portal](https://manage.windowsazure.com/).
2. At the bottom of the navigation pane, click **+NEW**.

3. Expand **Compute** and **Mobile Service**, then click **Create**.

This displays the **New Mobile Service** dialog.
4. In the **Create a mobile service** page, select **Create a free 20 MB SQL Database**, then type a subdomain name for the new mobile service in the **URL** textbox and wait for name verification. Once name verification completes, click the right arrow button to go to the next page.

This displays the **Specify database settings** page.
> [AZURE.NOTE] As part of this tutorial, you create a new SQL Database instance and server. You can reuse this new database and administer it as you would any other SQL Database instance. If you already have a database in the same region as the new mobile service, you can instead choose **Use existing Database** and then select that database. The use of a database in a different region is not recommended because of additional bandwidth costs and higher latencies.
5. In **Name**, type the name of the new database, then type **Login name**, which is the administrator login name for the new SQL Database server, type and confirm the password, and click the check button to complete the process.

> [AZURE.NOTE] When the password that you supply does not meet the minimum requirements or when there is a mismatch, a warning is displayed.
>
> We recommend that you make a note of the administrator login name and password that you specify; you will need this information to reuse the SQL Database instance or the server in the future.
You have now created a new mobile service that can be used by your mobile apps. Next, you will add a new table in which to store app data. This table will be used by the app in place of the in-memory collection.
To be able to store app data in the new mobile service, you must first create a new table.
1. In the Azure classic portal, click **Mobile Services**, and then click the mobile service that you just created.
2. Click the **Data** tab, then click **+Create**.
![][123]
This displays the **Create new table** dialog.
3. In **Table name** type _TodoItem_, then click the check button.
![][124]
This creates a new storage table **TodoItem** with the default permissions set, which means that any user of the app can access and change data in the table.
> [AZURE.NOTE] The same table name is used in Mobile Services quickstart. However, each table is created in a schema that is specific to a given mobile service. This is to prevent data collisions when multiple mobile services use the same database.
4. Click the new **TodoItem** table and verify that there are no data rows.
5. Click the **Columns** tab and verify that there is only a single **id** column, which is automatically created for you.
This is the minimum requirement for a table in Mobile Services.
> [AZURE.NOTE] When dynamic schema is enabled on your mobile service, new columns are created automatically when JSON objects are sent to the mobile service by an insert or update operation.
You are now ready to use the new mobile service as data storage for the app.
## Download and Configure the Starter Sample
We'll add push notifications to an existing sample.
1. Download the following sample: [Xamarin.Forms Azure Push Notification Starter Sample].
2. In the [Azure classic portal], click **Mobile Services**, and then click the mobile service. Click the **Dashboard** tab and make a note of the **Site URL**. Then click **Manage Keys** and make a note of the **Application Key**. You'll need these values when you access the mobile service from your app code.
3. In the **ToDoAzure(Portable)** project of the solution, open the **Constants.cs** file, replace `ApplicationURL` and `ApplicationKey` with the site URL and application key you obtained in the previous step.
## Add push notifications to your Xamarin.Forms.iOS app
You'll add push notifications to the iOS app by using the Apple Push Notification service (APNS). You'll need an active Google account, and the [Google Cloud Messaging Client Component].
>[AZURE.IMPORTANT] Because of Apple Push Notification service (APNS) requirements, you must deploy and test push notifications on an iOS capable device (iPhone or iPad) instead of in the emulator.
APNS uses certificates to authenticate your mobile service. Follow these instructions to create the necessary certificates and upload it to your Mobile Service. For the official APNS feature documentation, see [Apple Push Notification Service].
### Generate the Certificate Signing Request file
First you must generate the Certificate Signing Request (CSR) file, which is used by Apple to generate a signed certificate.
1. From Utilities, run the **Keychain Access tool**.
2. Click **Keychain Access**, expand **Certificate Assistant**, then click **Request a Certificate from a Certificate Authority...**.
![][5]
3. Enter your **User Email Address**, type in a **Common Name** value, make sure that **Saved to disk** is selected, and then click **Continue**.
![][6]
4. Type a name for the Certificate Signing Request (CSR) file in **Save As**, select the location in **Where**, then click **Save**.
![][7]
Remember the location you chose.
Next, you will register your app with Apple, enable push notifications, and upload this exported CSR to create a push certificate.
### Register your app for push notifications
To be able to send push notifications to an iOS app from mobile services, you must register your application with Apple and register for push notifications.
1. If you have not already registered your app, navigate to the iOS Provisioning Portal at the Apple Developer Center, log on with your Apple ID, click **Identifiers**, then click **App IDs**, and finally click on the **+** sign to create an app ID for your app.
![][102]
2. Type a name for your app in **Description**, enter and remember the unique **Bundle Identifier**, check the "Push Notifications" option in the "App Services" section, and then click **Continue**. This example uses the ID **MobileServices.Quickstart** but you may not reuse this same ID, as app IDs must be unique across all users. As such, it is recommended that you append your full name or initials after the app name.
![][103]
This generates your app ID and requests you to **Submit** the information. Click **Submit**.
![][104]
Once you click **Submit**, you will see the **Registration complete** screen, as shown below. Click **Done**.
![][105]
3. Locate the app ID that you just created, and click on its row.
![][106]
Clicking on the app ID will display details on the app and app ID. Click the **Settings** button.
![][107]
4. Scroll to the bottom of the screen, and click the **Create Certificate...** button under the section **Development Push SSL Certificate**.
![][108]
This displays the "Add iOS Certificate" assistant.
Note: This tutorial uses a development certificate. The same process is used when registering a production certificate. Just make sure that you set the same certificate type when you upload the certificate to Mobile Services.
5. Click **Choose File**, browse to the location where you saved the CSR file earlier, then click **Generate**.
![][110]
6. After the certificate is created by the portal, click the **Download** button, and click **Done**.
![][111]
This downloads the signing certificate and saves it to your computer in your Downloads folder.
![][9]
Note: By default, the downloaded file a development certificate is named aps_development.cer.
7. Double-click the downloaded push certificate **aps_development.cer**.
This installs the new certificate in the Keychain, as shown below:
![][10]
Note: The name in your certificate might be different, but it will be prefixed with Apple Development iOS Push Notification Services:.
Later, you will use this certificate to generate a .p12 file and upload it to Mobile Services to enable authentication with APNS.
### Create a provisioning profile for the app
1. Back in the iOS Provisioning Portal, select **Provisioning Profiles**, select **All**, and then click the **+** button to create a new profile. This launches the **Add iOS Provisiong Profile** Wizard.
![][112]
2. Select **iOS App Development** under **Development** as the provisiong profile type, and click **Continue**.
3. Next, select the app ID for the Mobile Services Quickstart app from the **App ID** drop-down list, and click **Continue**.
![][113]
4. In the **Select certificates** screen, select the certificate created earlier, and click **Continue**.
![][114]
5. Next, select the **Devices** to use for testing, and click **Continue**.
![][115]
6. Finally, pick a name for the profile in **Profile Name**, click **Generate**, and click **Done**.
![][116]
This creates a new provisioning profile.
![][117]
7. In Xcode, open the Organizer select the Devices view, select **Provisioning Profiles** in the **Library** section in the left pane, and then click the **Refresh** button at the bottom of the middle pane.
### Configure Mobile Services to send push requests
After you have registered your app with APNS and configured your project, you must next configure your mobile service to integrate with APNS.
1. In Keychain Access, right-click the new certificate, click **Export**, name your file, select the **.p12** format, then click **Save**.
![][28]
Make a note of the file name and location of the exported certificate.
2. Log on to the [Azure classic portal], click **Mobile Services**, and then click your app.
![][18]
3. Click the **Push** tab and click **Upload** under **apple push notification settings**.
![][19]
This displays the Upload Certificate dialog.
4. Click **File**, select the exported certificate .p12 file, enter the **Password**, make sure that the correct **Mode** is selected, click the check icon, then click **Save**.
![][20]
Your mobile service is now configured to work with APNS.
### Configure your Xamarin.iOS application
1. In Xamarin.Studio or Visual Studio, open **Info.plist**, and update the **Bundle Identifier** with the ID you created earlier.
![][121]
2. Scroll down to **Background Modes** and check the **Enable Background Modes** box and the **Remote notifications** box.
![][122]
3. Double click your project in the Solution Panel to open **Project Options**.
4. Choose **iOS Bundle Signing** under **Build**, and select the corresponding **Identity** and **Provisioning profile** you had just set up for this project.
![][120]
This ensures that the Xamarin project uses the new profile for code signing. For the official Xamarin device provisioning documentation, see [Xamarin Device Provisioning].
### Add push notifications to your app
1. In Xamarin.Studio or Visual Studio, expand the **ToDoAzure.iOS** project, open the **AppDelegate** class, and then replace the **FinishedLaunching** event with the following code:
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
// registers for push for iOS8
var settings = UIUserNotificationSettings.GetSettingsForTypes(
UIUserNotificationType.Alert
| UIUserNotificationType.Badge
| UIUserNotificationType.Sound,
new NSSet());
global::Xamarin.Forms.Forms.Init();
instance = this;
CurrentPlatform.Init();
todoItemManager = new ToDoItemManager();
App.SetTodoItemManager(todoItemManager);
UIApplication.SharedApplication.RegisterUserNotificationSettings(settings);
UIApplication.SharedApplication.RegisterForRemoteNotifications();
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
6. In **AppDelegate**, override the **RegisteredForRemoteNotifications** event:
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
// Modify device token
string _deviceToken = deviceToken.Description;
_deviceToken = _deviceToken.Trim('<', '>').Replace(" ", "");
// Get Mobile Services client
MobileServiceClient client = todoItemManager.GetClient();
// Register for push with Mobile Services
IEnumerable tag = new List() { "uniqueTag" };
const string template = "{\"aps\":{\"alert\":\"$(message)\"}}";
var expiryDate = DateTime.Now.AddDays(90).ToString
(System.Globalization.CultureInfo.CreateSpecificCulture("en-US"));
var push = client.GetPush();
push.RegisterTemplateAsync(_deviceToken, template, expiryDate, "myTemplate", tag);
}
7. In **AppDelegate**, override the **ReceivedRemoteNotification** event:
public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
{
NSObject inAppMessage;
bool success = userInfo.TryGetValue(new NSString("inAppMessage"), out inAppMessage);
if (success)
{
var alert = new UIAlertView("Got push notification", inAppMessage.ToString(), null, "OK", null);
alert.Show();
}
}
Your app is now updated to support push notifications.
### Update the registered insert script in the Azure classic portal
1. In the Azure classic portal, click the **Data** tab and then click the **TodoItem** table.
![][21]
2. In **todoitem**, click the **Script** tab and select **Insert**.
![][22]
This displays the function that is invoked when an insert occurs in the **TodoItem** table.
3. Replace the insert function with the following code, and then click **Save**:
function insert(item, user, request) {
// Execute the request and send notifications.
request.execute({
success: function() {
// Create a template-based payload.
var payload = '{ "message" : "New item added: ' + item.text + '" }';
// Write the default response and send a notification
// to all platforms.
push.send(null, payload, {
success: function(pushResponse){
console.log("Sent push:", pushResponse);
// Send the default response.
request.respond();
},
error: function (pushResponse) {
console.log("Error Sending push:", pushResponse);
// Send the an error response.
request.respond(500, { error: pushResponse });
}
});
}
});
}
This registers a new insert script, which sends a push notification (the inserted text) to the device provided in the insert request.
>[AZURE.NOTE] This script delays sending the notification to give you time to close the app to receive a toast notification.
### Test push notifications in your app
1. Press the **Run** button to build the project and start the app in an iOS capable device, then click **OK** to accept push notifications
>[AZURE.NOTE] You must explicitly accept push notifications from your app. This request only occurs the first time that the app runs.
2. In the app, click the **Add** button, add a task title and then click the **Save** button.
3. Verify that a notification is received, then click **OK** to dismiss the notification.
You have successfully completed this tutorial.
## Add push notifications to the Xamarin.Forms.Android app
You'll add push notifications to the Android app by using the Google Cloud Messaging (GCM) service. You'll need an active Google account, and the [Google Cloud Messaging Client Component].
### Enable Google Cloud Messaging
1. Navigate to the [Google Cloud Console](https://console.developers.google.com/project), sign in with your Google account credentials.
2. Click **Create Project**, type a project name, then click **Create**. If requested, carry out the SMS Verification, and click **Create** again.

Type in your new **Project name** and click **Create project**.
3. Click the **Utilities and More** button and then click **Project Information**. Make a note of the **Project Number**. You will need to set this value as the `SenderId` variable in the client app.

4. In the project dashboard, under **Mobile APIs**, click **Google Cloud Messaging**, then on the next page click **Enable API** and accept the terms of service.


5. In the project dashboard, Click **Credentials** > **Create Credential** > **API Key**.

6. In **Create a new key**, click **Server key**, type a name for your key, then click **Create**.
7. Make a note of the **API KEY** value.
You will use this API key value to enable Azure to authenticate with GCM and send push notifications on behalf of your app.
### Configure your mobile service to send push requests
1. Log on to the [Azure classic portal](https://manage.windowsazure.com/), click **Mobile Services**, and then click your app.
2. Click the **Push** tab, enter the **API Key** value obtained from GCM in the previous procedure, then click **Save**.

>[AZURE.NOTE]When you set your GCM credentials for enhanced push notifications in the Push tab in the portal, they are shared with Notification Hubs to configure the notification hub with your app.
Both your mobile service and your app are now configured to work with GCM and Notification Hubs.
### Update the registered insert script to send notifications
>[AZURE.NOTE] The following steps show you how to update the script registered to the insert operation on the TodoItem table in the Azure classic portal. You can also access and edit this mobile service script directly in Visual Studio, in the Azure node of Server Explorer.
In the [Azure classic portal], click the **Data** tab and then click the **TodoItem** table.
![][21]
2. In **todoitem**, click the **Script** tab and select **Insert**.
![][22]
This displays the function that is invoked when an insert occurs in the **TodoItem** table.
3. Replace the insert function with the following code, and then click **Save**:
function insert(item, user, request) {
// Execute the request and send notifications.
request.execute({
success: function() {
// Create a template-based payload.
var payload = '{ "message" : "New item added: ' + item.text + '" }';
// Write the default response and send a notification
// to all platforms.
push.send(null, payload, {
success: function(pushResponse){
console.log("Sent push:", pushResponse);
// Send the default response.
request.respond();
},
error: function (pushResponse) {
console.log("Error Sending push:", pushResponse);
// Send the an error response.
request.respond(500, { error: pushResponse });
}
});
}
});
}
This registers a new insert script, which sends a push notification (the inserted text) to the device provided in the insert request.
>[AZURE.NOTE] This script delays sending the notification to give you time to close the app to receive a toast notification.
### Configure the existing project for push notifications
1. In the Solution view, expand the **Components** folder in the Xamarin.Android app and make sure that Azure Mobile Services package is installed.
2. Right-click the **Components** folder, click **Get More Components...**, search for the **Google Cloud Messaging Client** component and add it to the project.
1. Open the MainActivity.cs project file and add the following using statement to the class:
using Gcm.Client;
4. In the **MainActivity** class, add the following code to the **OnCreate** method, after the call to the **LoadApplication** method:
try
{
// Check to ensure everything's setup right
GcmClient.CheckDevice(this);
GcmClient.CheckManifest(this);
// Register for push notifications
System.Diagnostics.Debug.WriteLine("Registering...");
GcmClient.Register(this, PushHandlerBroadcastReceiver.SENDER_IDS);
}
catch (Java.Net.MalformedURLException)
{
CreateAndShowDialog(new Exception("There was an error creating the Mobile Service. Verify the URL"), "Error");
}
catch (Exception e)
{
CreateAndShowDialog(e, "Error");
}
Your **MainActivity** is now prepared for adding push notifications.
### Add push notifications code to your app
5. In the ToDoAzure.Droid project, create a new class in the project called `GcmService`.
5. Add the following using statements to **GcmService** class:
using Gcm.Client;
using Microsoft.WindowsAzure.MobileServices;
6. Add the following permission requests between the **using** statements and the **namespace** declaration:
[assembly: Permission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "com.google.android.c2dm.permission.RECEIVE")]
//GET_ACCOUNTS is only needed for android versions 4.0.3 and below
[assembly: UsesPermission(Name = "android.permission.GET_ACCOUNTS")]
[assembly: UsesPermission(Name = "android.permission.INTERNET")]
[assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
7. In the **GcmService.cs** project file, add the following class:
[BroadcastReceiver(Permission = Gcm.Client.Constants.PERMISSION_GCM_INTENTS)]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_MESSAGE }, Categories = new string[] { "@PACKAGE_NAME@" })]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_REGISTRATION_CALLBACK }, Categories = new string[] { "@PACKAGE_NAME@" })]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_LIBRARY_RETRY }, Categories = new string[] { "@PACKAGE_NAME@" })]
public class PushHandlerBroadcastReceiver : GcmBroadcastReceiverBase
{
public static string[] SENDER_IDS = new string[] { "" };
}
In the above code, you must replace _``_ with the project number assigned by Google when you provisioned your app in the Google developer portal.
8. In the GcmService.cs project file, add the following code that defines the **GcmService** class:
[Service]
public class GcmService : GcmServiceBase
{
public static string RegistrationID { get; private set; }
public GcmService()
: base(PushHandlerBroadcastReceiver.SENDER_IDS){}
}
Note that this class derives from **GcmServiceBase** and that the **Service** attribute must be applied to this class.
>[AZURE.NOTE]The **GcmServiceBase** class implements the **OnRegistered()**, **OnUnRegistered()**, **OnMessage()** and **OnError()** methods. You must override these methods in the **GcmService** class.
5. Add the following code to the **GcmService** class that overrides the **OnRegistered** event handler.
protected override void OnRegistered(Context context, string registrationId)
{
Log.Verbose(PushHandlerBroadcastReceiver.TAG, "GCM Registered: " + registrationId);
RegistrationID = registrationId;
createNotification("GcmService Registered...", "The device has been Registered, Tap to View!");
MobileServiceClient client = MainActivity.DefaultService.todoItemManager.GetClient;
var push = client.GetPush();
MainActivity.DefaultService.RunOnUiThread(() => Register(push, null));
}
public async void Register(Microsoft.WindowsAzure.MobileServices.Push push, IEnumerable tags)
{
try
{
const string template = "{\"data\":{\"message\":\"$(message)\"}}";
await push.RegisterTemplateAsync(RegistrationID, template, "mytemplate", tags);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
Debugger.Break();
}
}
This method uses the returned GCM registration ID to register with Azure for push notifications.
10. Override the **OnMessage** method in **GcmService** with the following code:
protected override void OnMessage(Context context, Intent intent)
{
Log.Info(PushHandlerBroadcastReceiver.TAG, "GCM Message Received!");
var msg = new StringBuilder();
if (intent != null && intent.Extras != null)
{
foreach (var key in intent.Extras.KeySet())
msg.AppendLine(key + "=" + intent.Extras.Get(key).ToString());
}
//Store the message
var prefs = GetSharedPreferences(context.PackageName, FileCreationMode.Private);
var edit = prefs.Edit();
edit.PutString("last_msg", msg.ToString());
edit.Commit();
string message = intent.Extras.GetString("message");
if (!string.IsNullOrEmpty(message))
{
createNotification("New todo item!", "Todo item: " + message);
return;
}
string msg2 = intent.Extras.GetString("msg");
if (!string.IsNullOrEmpty(msg2))
{
createNotification("New hub message!", msg2);
return;
}
createNotification("Unknown message details", msg.ToString());
}
void createNotification(string title, string desc)
{
//Create notification
var notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
//Create an intent to show ui
var uiIntent = new Intent(this, typeof(MainActivity));
//Create the notification
var notification = new Notification(Android.Resource.Drawable.SymActionEmail, title);
//Auto cancel will remove the notification once the user touches it
notification.Flags = NotificationFlags.AutoCancel;
//Set the notification info
//we use the pending intent, passing our ui intent over which will get called
//when the notification is tapped.
notification.SetLatestEventInfo(this, title, desc, PendingIntent.GetActivity(this, 0, uiIntent, 0));
//Show the notification
notificationManager.Notify(1, notification);
}
12. Add the following method overrides for **OnUnRegistered()** and **OnError()**, which are required for the project to compile.
protected override void OnUnRegistered(Context context, string registrationId)
{
Log.Error("GcmService", "Unregistered RegisterationId : " + registrationId);
}
protected override void OnError(Context context, string errorId)
{
Log.Error(PushHandlerBroadcastReceiver.TAG, "GCM Error: " + errorId);
}
### Test push notifications in your app
You can test the app by directly attaching an Android phone with a USB cable, or by using a virtual device in the emulator.
When you run this app in the emulator, make sure that you use an Android Virtual Device (AVD) that supports Google APIs.
> [AZURE.IMPORTANT] In order to receive push notifications, you must set up a Google account on your Android Virtual Device (in the emulator, navigate to **Settings** and click **Add Account**). Also, make sure that the emulator is connected to the Internet.
1. From **Tools**, click **Open Android Emulator Manager**, select your device, and then click **Edit**.
![][125]
2. Select **Google APIs** in **Target**, then click **OK**.
![][126]
3. On the top toolbar, click **Run**, and then select your app. This starts the emulator and runs the app.
The app retrieves the *registrationId* from GCM and registers with the Notification Hub.
1. In the app, add a new task.
2. Swipe down from the top of the screen to open the device's Notification Center to see the notification.
![][127]
## Add push notifications to the Xamarin.Forms.Windows app
This section shows you how to use Azure Mobile Services to send push notifications to the Windows Phone Silverlight app that is included in your Xamarin.Forms solution.
### Update the app to register for notifications
Before your app can receive push notifications, you must register a notification channel.
1. In Visual Studio, open the file App.xaml.cs and add the following `using` statement:
using Microsoft.Phone.Notification;
3. Add the following to App.xaml.cs:
public static HttpNotificationChannel CurrentChannel { get; private set; }
private void AcquirePushChannel()
{
CurrentChannel = HttpNotificationChannel.Find("MyPushChannel");
if (CurrentChannel == null)
{
CurrentChannel = new HttpNotificationChannel("MyPushChannel");
CurrentChannel.Open();
CurrentChannel.BindToShellToast();
}
CurrentChannel.ChannelUriUpdated +=
new EventHandler(async (o, args) =>
{
// Register for notifications using the new channel
const string template =
"$(message)";
await client.GetPush()
.RegisterTemplateAsync(CurrentChannel.ChannelUri.ToString(), template, "mytemplate");
});
}
This code retrieves the ChannelURI for the app from the Microsoft Push Notification Service (MPNS) used by Windows Phone 8.x "Silverlight", and then registers that ChannelURI for push notifications.
>[AZURE.NOTE]In this this tutorial, the mobile service sends a toast notification to the device. When you send a tile notification, you must instead call the **BindToShellTile** method on the channel.
4. At the top of the **Application_Launching** event handler in App.xaml.cs, add the following call to the new **AcquirePushChannel** method:
AcquirePushChannel();
This makes sure that registration is requested every time that the page is loaded. In your app, you may only want to make this registration periodically to ensure that the registration is current.
5. Press the **F5** key to run the app. A popup dialog with the registration key is displayed.
6. In the Solution Explorer, expand **Properties**, open the WMAppManifest.xml file, click the **Capabilities** tab and make sure that the **ID_CAP_PUSH_NOTIFICATION** capability is checked.

This makes sure that your app can raise toast notifications.
### Update server scripts to send push notifications
Finally, you must update the script registered to the insert operation on the TodoItem table to send notifications.
1. In the [Azure classic portal], click the **Data** tab and then click the **TodoItem** table.
![][21]
2. In **todoitem**, click the **Script** tab and select **Insert**.
![][22]
This displays the function that is invoked when an insert occurs in the **TodoItem** table.
3. Replace the insert function with the following code, and then click **Save**:
function insert(item, user, request) {
// Execute the request and send notifications.
request.execute({
success: function() {
// Create a template-based payload.
var payload = '{ "message" : "New item added: ' + item.text + '" }';
// Write the default response and send a notification
// to all platforms.
push.send(null, payload, {
success: function(pushResponse){
console.log("Sent push:", pushResponse);
// Send the default response.
request.respond();
},
error: function (pushResponse) {
console.log("Error Sending push:", pushResponse);
// Send the an error response.
request.respond(500, { error: pushResponse });
}
});
}
});
}
This registers a new insert script, which sends a push notification (the inserted text) to the device provided in the insert request.
3. Click the **Push** tab, check **Enable unauthenticated push notifications**, then click **Save**.
This enables the mobile service to connect to MPNS in unauthenticated mode to send push notifications.
>[AZURE.NOTE]This tutorial uses MPNS in unauthenticated mode. In this mode, MPNS limits the number of notifications that can be sent to a device channel. To remove this restriction, you must generate and upload a certificate by clicking **Upload** and selecting the certificate. For more information on generating the certificate, see [Setting up an authenticated web service to send push notifications for Windows Phone].
### Test push notifications in your app
1. In Visual Studio, press the F5 key to run the app.
>[AZURE.NOTE] You may encounter a 401 Unauthorized RegistrationAuthorizationException when testing on the Windows Phone emulator. This can occur during the `RegisterNativeAsync()` call because of the way the Windows Phone emulator syncs it's clock with the host PC. It can result in a security token that will be rejected. To resolve this simply manually set the clock in the emulator before testing.
5. In the app, create a new task with the title **Hello push**, then immediately click the start button or back button to leave the app.
This sends an insert request to the mobile service to store the added item. Notice that the device receives a toast notification that says **hello push**.

>[AZURE.NOTE]You will not receive the notification when you are still in the app. To receive a toast notification while the app is active, you must handle the [ShellToastNotificationReceived](http://msdn.microsoft.com/library/windowsphone/develop/microsoft.phone.notification.httpnotificationchannel.shelltoastnotificationreceived(v=vs.105).aspx) event.
[Generate the certificate signing request]: #certificates
[Register your app and enable push notifications]: #register
[Create a provisioning profile for the app]: #profile
[Configure Mobile Services]: #configure-mobileServices
[Configure the Xamarin.iOS App]: #configure-app
[Update scripts to send push notifications]: #update-scripts
[Add push notifications to the app]: #add-push
[Insert data to receive notifications]: #test
[5]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-step5.png
[6]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-step6.png
[7]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-step7.png
[9]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-step9.png
[10]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-step10.png
[17]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-step17.png
[18]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-selection.png
[19]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-push-tab-ios.png
[20]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-push-tab-ios-upload.png
[21]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-portal-data-tables.png
[22]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-insert-script-push2.png
[23]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-quickstart-push1-ios.png
[24]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-quickstart-push2-ios.png
[25]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-quickstart-push3-ios.png
[26]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-quickstart-push4-ios.png
[28]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-step18.png
[101]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-01.png
[102]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-02.png
[103]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-03.png
[104]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-04.png
[105]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-05.png
[106]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-06.png
[107]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-07.png
[108]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-08.png
[110]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-10.png
[111]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-11.png
[112]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-12.png
[113]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-13.png
[114]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-14.png
[115]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-15.png
[116]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-16.png
[117]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-17.png
[120]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-20.png
[121]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-21.png
[122]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-services-ios-push-22.png
[123]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-data-tab-empty.png
[124]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/mobile-create-todoitem-table.png
[125]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/notification-hub-create-android-app7.png
[126]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/notification-hub-create-android-app8.png
[127]: ./media/partner-xamarin-mobile-services-xamarin-forms-get-started-push/notification-area-received.png
[Xamarin Studio]: http://xamarin.com/download
[Install Xcode]: https://go.microsoft.com/fwLink/p/?LinkID=266532
[iOS Provisioning Portal]: http://go.microsoft.com/fwlink/p/?LinkId=272456
[Mobile Services iOS SDK]: https://go.microsoft.com/fwLink/p/?LinkID=266533
[Apple Push Notification Service]: http://go.microsoft.com/fwlink/p/?LinkId=272584
[Get started with Mobile Services]: mobile-services-ios-get-started.md
[Xamarin Device Provisioning]: http://developer.xamarin.com/guides/ios/getting_started/installation/device_provisioning/
[Azure classic portal]: https://manage.windowsazure.com/
[apns object]: http://go.microsoft.com/fwlink/p/?LinkId=272333
[Azure Mobile Services Component]: http://components.xamarin.com/view/azure-mobile-services/
[completed example project]: http://go.microsoft.com/fwlink/p/?LinkId=331303
[Google Cloud Messaging Client Component]: http://components.xamarin.com/view/GCMClient/
[Xamarin.Forms Azure Push Notification Starter Sample]: https://github.com/Azure/mobile-services-samples/tree/master/TodoListXamarinForms
[Completed Xamarin.Forms Azure Push Notification Sample]: https://github.com/Azure/mobile-services-samples/tree/master/GettingStartedWithPushXamarinForms
================================================
FILE: docs/store-sendgrid-mobile-services-send-email-scripts.md
================================================
# Send email from Mobile Services with SendGrid
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
This topic shows you how can add email functionality to your mobile service. In this tutorial you add server side scripts to send email using SendGrid. When complete, your mobile service will send an email each time a record is inserted.
SendGrid is a [cloud-based email service] that provides reliable [transactional email delivery], scalability, and real-time analytics along with flexible APIs that make custom integration easy. For more information, see .
This tutorial walks you through these basic steps to enable email functionality:
1. [Create a SendGrid account]
2. [Add a script to send email]
3. [Insert data to receive email]
This tutorial is based on the Mobile Services quickstart. Before you start this tutorial, you must first complete [Get started with Mobile Services].
## Create a new SendGrid account
Azure customers can unlock 25,000 free emails each month. These 25,000 free monthly emails will give you access to advanced reporting and analytics and [all APIs][] (Web, SMTP, Event, Parse and more). For information about additional services provided by SendGrid, see the [SendGrid Features][] page.
### To sign up for a SendGrid account
1. Log in to the [Azure Management Portal][].
2. In the lower pane of the management portal, click **New**.
![command-bar-new][command-bar-new]
3. Click **Marketplace**.
![sendgrid-store][sendgrid-store]
4. In the **Choose an Application and Service** dialog, select **SendGrid** and click the right arrow.
5. In the **Personalize Application and Service** dialog select the **SendGrid** plan you want to sign up for.
6. Enter a name to identify your **SendGrid** service in your Azure settings, or use the default value of **SendGridEmailDelivery.Simplified.SMTPWebAPI**. Names must be between 1 and 100 characters in length and contain only alphanumeric characters, dashes, dots, and underscores. The name must be unique in your list of subscribed Azure Store Items.
![store-screen-2][store-screen-2]
7. Choose a value for the region; for example, West US.
8. Click the right arrow.
9. On the **Review Purchase** tab, review the plan and pricing information, and review the legal terms. If you agree to the terms, click the check mark. After you click the check mark, your SendGrid account will begin the [SendGrid provisioning process].
![store-screen-3][store-screen-3]
10. After confirming your purchase you are redirected to the add-ons dashboard and you will see the message **Purchasing SendGrid**.
![sendgrid-purchasing-message][sendgrid-purchasing-message]
Your SendGrid account is provisioned immediately and you will see the message **Successfully purchased Add-On SendGrid**. Your account and credentials are now created. You are ready to send emails at this point.
To modify your subscription plan or see the SendGrid contact settings, click the name of your SendGrid service to open the SendGrid Marketplace dashboard.
![sendgrid-add-on-dashboard][sendgrid-add-on-dashboard]
To send an email using SendGrid, you must supply your account credentials (username and password).
### To find your SendGrid credentials ###
1. Click **Connection Info**.
![sendgrid-connection-info-button][sendgrid-connection-info-button]
2. In the *Connection info* dialog, copy the **Password** and Username to use later in this tutorial.
![sendgrid-connection-info][sendgrid-connection-info]
To set your email deliverability settings, click the **Manage** button. This will redirect to your SendGrid Control Panel.
![sendgrid-control-panel][sendgrid-control-panel]
For more information on getting started with SendGrid, see [SendGrid Getting Started][].
## Register a new script that sends emails
1. Log on to the [Azure classic portal], click **Mobile Services**, and then click your mobile service.
2. In the Azure classic portal, click the **Data** tab and then click the **TodoItem** table.
![][1]
3. In **todoitem**, click the **Script** tab and select **Insert**.
![][2]
This displays the function that is invoked when an insert occurs in the **TodoItem** table.
4. Replace the insert function with the following code:
var SendGrid = require('sendgrid').SendGrid;
function insert(item, user, request) {
request.execute({
success: function() {
// After the record has been inserted, send the response immediately to the client
request.respond();
// Send the email in the background
sendEmail(item);
}
});
function sendEmail(item) {
var sendgrid = new SendGrid('**username**', '**password**');
sendgrid.send({
to: '**email-address**',
from: '**from-address**',
subject: 'New to-do item',
text: 'A new to-do was added: ' + item.text
}, function(success, message) {
// If the email failed to send, log it as an error so we can investigate
if (!success) {
console.error(message);
}
});
}
}
5. Replace the placeholders in the above script with the correct values:
- **_username_ and _password_**: the SendGrid credentials you identified in [Create a SendGrid account].
- **_email-address_**: the address that the email is sent to. In a real-world app, you can use tables to store and retrieve email addresses. When testing your app, just use your own email address.
- **_from-address_**: the address from which the email originates. Consider using a registered domain address that belongs to your organization.
> [AZURE.NOTE] If you do not have a registered domain, you can instead use the domain of your Mobile Service, in the format *notifications@_your-mobile-service_.azure-mobile.net*. However, messages sent to your mobile service domain are ignored.
6. Click the **Save** button. You have now configured a script to send an email each time a record is inserted into the **TodoItem** table.
## Insert test data to receive email
1. In the client app project, run the quickstart application.
This topic shows the Windows Store version of the quickstart,
2. In the app, type text in **Insert a TodoItem**, and then click **Save**.
![][3]
3. Notice that you receive an email, such as one shown in the notification below.
![][4]
Congratulations, you have successfully configured your mobile service to send email by using SendGrid.
## Next Steps
Now that you've seen how easy it is to use the SendGrid email service with Mobile Services, follow
these links to learn more about SendGrid.
- SendGrid API documentation:
- SendGrid special offer for Azure customers:
[command-bar-new]: ./media/sendgrid-sign-up/sendgrid_BAR_NEW.PNG
[sendgrid-store]: ./media/sendgrid-sign-up/sendgrid_offerings_store.png
[store-screen-2]: ./media/sendgrid-sign-up/sendgrid_store_scrn2.png
[store-screen-3]: ./media/sendgrid-sign-up/sendgrid_store_scrn3.png
[sendgrid-purchasing-message]: ./media/sendgrid-sign-up/sendgrid_purchasing_message.png
[sendgrid-add-on-dashboard]: ./media/sendgrid-sign-up/sendgrid_add-on_dashboard.png
[sendgrid-connection-info]: ./media/sendgrid-sign-up/sendgrid_connection_info.png
[sendgrid-connection-info-button]: ./media/sendgrid-sign-up/sendgrid_connection_info_button.png
[sendgrid-control-panel]: ./media/sendgrid-sign-up/sendgrid_control_panel.png
[SendGrid Features]: http://sendgrid.com/features
[Azure Management Portal]: https://manage.windowsazure.com
[SendGrid Getting Started]: http://sendgrid.com/docs
[SendGrid Provisioning Process]: https://support.sendgrid.com/hc/articles/200181628-Why-is-my-account-being-provisioned-
[all APIs]: https://sendgrid.com/docs/API_Reference/index.html
[Create a SendGrid account]: #sign-up
[Add a script to send email]: #add-script
[Insert data to receive email]: #insert-data
[1]: ./media/store-sendgrid-mobile-services-send-email-scripts/mobile-portal-data-tables.png
[2]: ./media/store-sendgrid-mobile-services-send-email-scripts/mobile-insert-script-push2.png
[3]: ./media/store-sendgrid-mobile-services-send-email-scripts/mobile-quickstart-push1.png
[4]: ./media/store-sendgrid-mobile-services-send-email-scripts/mobile-receive-email.png
[Get started with Mobile Services]: https://azure.microsoft.com/develop/mobile/tutorials/get-started
[sign up page]: https://sendgrid.com/windowsazure.html
[Multiple User Credentials page]: https://sendgrid.com/credentials
[Azure classic portal]: https://manage.windowsazure.com/
[cloud-based email service]: https://sendgrid.com/email-solutions
[transactional email delivery]: https://sendgrid.com/transactional-email
================================================
FILE: docs/vs-mobile-services-cordova-getting-started.md
================================================
# Getting Started with Mobile Services (Cordova Projects)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
## First steps
The first step you need to do in order to follow the code in these examples depends on what type of mobile service you connected to.
- For a JavaScript backend mobile service, create a table called TodoItem. To create a table, locate the mobile service under
the Azure node in Server Explorer, right-click the mobile service's node to open the context menu, and choose **Create Table**.
Enter "TodoItem" as the table name.
- If you have a .NET backend mobile service, there's already a TodoItem table in the default project template that Visual Studio
created for you, but you need to publish it to Azure. To publish it, open the context menu for the mobile service project in
Solution Explorer, and choose **Publish Web**. Accept the defaults, and choose the **Publish** button.
## Create a reference to a table
The following code gets a reference to a table that contains data for a TodoItem, which you can use in subsequent operations to
read and update the data table. The TodoItem table is created automatically when you create a mobile service.
var todoTable = mobileServiceClient.getTable('TodoItem');
For these examples to work, permissions on the table must be set to **Anybody with an Application Key**. Later, you can set
up authentication. See [Get started with authentication](mobile-services-html-get-started-users.md).
## Add an item to a table
Insert a new item into a data table. An id (a GUID of type string) is automatically created as the primary key for the new
row. Call the **done** method on the returned [Promise](https://msdn.microsoft.com/library/dn802826.aspx) object to get a
copy of the inserted object and handle any errors.
function TodoItem(text) {
this.text = text;
this.complete = false;
}
var items = new Array();
var insertTodoItem = function (todoItem) {
todoTable.insert(todoItem).done(function (item) {
items.push(item)
});
};
## Read or query a table
The following code queries a table for all items, sorted by the text field. You can add code to process the query results
in the success handler. In this case, a local array of the items is updated.
todoTable.orderBy('text')
.read().done(function (results) {
items = results.slice();
});
You can use the where method to modify the query. Here's an example that filters out completed items.
todoTable.where(function () {
return (this.complete === false);
})
.read().done(function (results) {
items = results.slice();
});
For more examples of queries you can use, see [query](https://msdn.microsoft.com/library/azure/jj613353.aspx) object.
## Update a table item
Update a row in a data table. In this code, when the mobile service responds, the item is removed from the
list. Call the **done** method on the returned [Promise](https://msdn.microsoft.com/library/dn802826.aspx) object to
get a copy of the inserted object and handle any errors.
todoTable.update(todoItem).done(function (item) {
// Update a local collection of items.
items.splice(items.indexOf(todoItem), 1, item);
});
## Delete a table item
Delete a row in a data table using the **del** method. Call the **done** method on the returned
[Promise](https://msdn.microsoft.com/library/dn802826.aspx) object to get a copy of the inserted object
and handle any errors.
todoTable.del(todoItem).done(function (item) {
items.splice(items.indexOf(todoItem), 1);
});
================================================
FILE: docs/vs-mobile-services-cordova-what-happened.md
================================================
# What happened to my Azure Cordova project after adding Azure Mobile Services by using Visual Studio Connected Services?
## References Added
The Azure Mobile Service Client plugin included with all Multi-Device Hybrid Apps has been enabled.
## Connection string values for Mobile Services
Under `services\mobileServices\settings`, a new JavaScript (.js) file with a **MobileServiceClient** was generated containing the selected mobile service’s application URL and application key. The file contains the initialization of a mobile service client object, similar to the following code.
var mobileServiceClient;
document.addEventListener("deviceready", function() {
mobileServiceClient = new WindowsAzure.MobileServiceClient(
".azure-mobile.net",
""
);
[Learn more about mobile services](https://azure.microsoft.com/documentation/services/mobile-services/)
================================================
FILE: docs/vs-mobile-services-dotnet-getting-started.md
================================================
# Getting Started with Mobile Services (.NET Projects)
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
The first step you need to do in order to follow the code in these examples depends on what type of mobile service you connected to.
- For a JavaScript backend mobile service, create a table called TodoItem. To create a table, locate the mobile service under the Azure node in Server Explorer, right-click the mobile service's node to open the context menu, and choose **Create Table**. Enter "TodoItem" as the table name.
- If you have a .NET backend mobile service, there's already a TodoItem table in the default project template that Visual Studio created for you, but you need to publish it to Azure. To publish it, open the context menu for the mobile service project in Solution Explorer, and choose **Publish Web**. Accept the defaults, and choose the **Publish** button.
## Get a reference to a table
The following code creates a reference to a table (`todoTable`) that contains data for a TodoItem, which you can use in subsequent operations to read and update the data table. You'll need the TodoItem class with attributes set up to interpet the JSON that the mobile service sends in response to your queries.
public class TodoItem
{
public string Id { get; set; }
[JsonProperty(PropertyName = "text")]
public string Text { get; set; }
[JsonProperty(PropertyName = "complete")]
public bool Complete { get; set; }
}
IMobileServiceTable todoTable = App..GetTable();
This code works if your table has permissions set to **Anybody with an Application Key**. If you change the permissions to secure your mobile service, you'll need to add user authentication support. See [Get Started with Authentication](mobile-services-dotnet-backend-windows-universal-dotnet-get-started-users.md).
## Add a table item
Insert a new item into a data table.
TodoItem todoItem = new TodoItem() { Text = "My first to do item", Complete = false };
await todoTable.InsertAsync(todoItem);
## Read or query a table
The following code queries a table for all items. Note that it returns only the first page of data, which by default is 50 items. You can pass the page size you want, since it's an optional parameter.
List items;
try
{
// Query that returns all items.
items = await todoTable.ToListAsync();
}
catch (MobileServiceInvalidOperationException e)
{
// handle exception
}
## Update a table item
Update a row in a data table. The parameter item is the TodoItem object to be updated.
await todoTable.UpdateAsync(item);
## Delete a table item
Delete a row in the database. The parameter item is the TodoItem object to be deleted.
await todoTable.DeleteAsync(item);
[Learn more about mobile services](https://azure.microsoft.com/documentation/services/mobile-services/)
================================================
FILE: docs/vs-mobile-services-dotnet-what-happened.md
================================================
# What happened to my Visual Studio .NET project after adding Azure Mobile Services by using Connected Services?
>[AZURE.WARNING] This is an **Azure Mobile Services** topic. This service has been superseded by Azure App Service Mobile Apps and is scheduled for removal from Azure. We recommend using Azure Mobile Apps for all new mobile backend deployments. Read [this announcement](https://azure.microsoft.com/blog/transition-of-azure-mobile-services/) to learn more about the pending deprecation of this service.
>
> Learn about [migrating your site to Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-migrating-from-mobile-services/).
>
> Get started with Azure Mobile Apps, see the [Azure Mobile Apps documentation center](https://azure.microsoft.com/documentation/learning-paths/appservice-mobileapps/).
## References Added
The Azure Mobile Services NuGet package was added to your project. As a result, the following .NET references were added to your project:
- **Microsoft.WindowsAzure.Mobile**
- **Microsoft.WindowsAzure.Mobile.Ext**
- **Newtonsoft.Json**
- **System.Net.Http.Extensions**
- **System.Net.Http.Primitives**
## Connection string values for Mobile Services
In your App.xaml.cs file, a **MobileServiceClient** object was created with the selected mobile service’s application URL and application key.
## Mobile Services project added
If a .NET mobile service is created in the Connected Service Provider, then a mobile services project is created and added to the solution.
[Learn more about mobile services](https://azure.microsoft.com/documentation/services/mobile-services/)
================================================
FILE: docs/vs-mobile-services-javascript-getting-started.md
================================================
# Getting Started with with a Javascript mobile app after adding Azure Mobile Services by using Visual Studio Connected Services
The first step you need to do in order to follow the code in these examples depends on what type of mobile service you connected to.
- For a JavaScript backend mobile service, create a table called TodoItem. To create a table, locate the mobile service under the Azure node in Server Explorer, right-click the mobile service's node to open the context menu, and choose **Create Table**. Enter "TodoItem" as the table name.
- If instead you have a .NET backend mobile service, there's already a TodoItem table in the default project template that Visual Studio created for you, but you need to publish it to Azure. To publish it, open the context menu for the mobile service project in Solution Explorer, and choose **Publish Web**. Accept the defaults, and choose the **Publish** button.
## Get a reference to a table
The client object was added to your project already. Its name is the name of your mobile service with "Client" appended to it. The following code gets a reference to a table that contains data for a TodoItem, which you can use in subsequent operations to read and update the data table.
var todoTable = yourMobileServiceClient.getTable('TodoItem');
## Add an entry
Insert a new item into a data table. An id (a GUID of type string) is automatically created as the primary key for the new row. Don't change the type of the id column, since the mobile services infrastructure uses it.
var todoTable = client.getTable('TodoItem');
var todoItems = new WinJS.Binding.List();
var insertTodoItem = function (todoItem) {
todoTable.insert(todoItem).done(function (item) {
todoItems.push(item);
});
};
## Read/query a table
The following code queries a table for all items, updates a local collection and binds the result to the UI element listItems.
// This code refreshes the entries in the list view
// by querying the TodoItems table.
todoTable.where()
.read()
.done(function (results) {
todoItems = new WinJS.Binding.List(results);
listItems.winControl.itemDataSource = todoItems.dataSource;
});
You can use the where method to modify the query. Here's an example that filters out completed items.
todoTable.where(function () {
return (this.complete === false && this.createdAt !== null);
})
.read()
.done(function (results) {
todoItems = new WinJS.Binding.List(results);
listItems.winControl.itemDataSource = todoItems.dataSource;
});
For more examples of queries you can use, see [query object](http://msdn.microsoft.com/library/azure/jj613353.aspx).
## Update an entry
Update a row in a data table. In this example, *todoItem* is the updated item, and *item* is the same item as returned from the mobile service. When the mobile service responds, the item is updated in the local todoItems list using the [splice](http://msdn.microsoft.com/library/windows/apps/Hh700810.aspx) method. Call the **done** method on the returned [Promise](https://msdn.microsoft.com/library/dn802826.aspx) object to get a copy of the inserted object and handle any errors.
todoTable.update(todoItem).done(function (item) {
todoItems.splice(todoItems.indexOf(item), 1, item);
});
## Delete an entry
Delete a row in a data table. Call the [done]() method on the returned [Promise](https://msdn.microsoft.com/library/dn802826.aspx) object to get a copy of the inserted object and handle any errors.
todoTable.del(todoItem).done(function (item) {
todoItems.splice(todoItems.indexOf(item), 1);
}
[Learn more about mobile services](https://azure.microsoft.com/documentation/services/mobile-services/)
================================================
FILE: docs/vs-mobile-services-javascript-what-happened.md
================================================
# What happens to my Javascript project when I add Azure Mobile Services using Connected Visual Studio Services?
## NuGet package added
The **WindowsAzure.MobileServices.WinJS** NuGet package was installed, including the Azure Mobile Service library in the `js\MobileServices.js` file.
## Connection string values for Mobile Services
In the `services\mobileServices\settings` folder, a new JavaScript (.js) file with a **MobileServiceClient** was generated that contains the selected mobile service's application URL and application key.
## References added to default.html
References to `MobileServices.js` and the settings file were added to `default.html`.
## Connected services files added
In the services folder, Connected Services configuration files were added.
================================================
FILE: sdk/Javascript/.gitignore
================================================
*.suo
#ignore build files
bin
obj
bld
*.jsproj.user
test/*/js/MobileServices.*
packages/*
#just in case ignore the folders we pull from git (if a delete fails in the build process)
tools/JSBuild/queryjs/*
tools/JSBuild/esprima/*
node_modules
================================================
FILE: sdk/Javascript/Gruntfile.js
================================================
///
module.exports = function (grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
files: {
resources: [
'src/Strings/**/Resources.resjson'
],
core: [
'src/Utilities/Extensions.js',
'src/MobileServiceClient.js',
'src/MobileServiceTable.js',
'src/MobileServiceLogin.js',
'src/Push/RegistrationManager.js',
'src/Push/LocalStorageManager.js',
'src/Push/PushHttpClient.js',
'src/Utilities/Validate.js',
'src/External/queryjs/lib/*.js',
'src/External/esprima/esprima.js'
],
web: [
'src/Push/Push.Web.js',
'src/Platforms/Platform.Web.js',
'src/Generated/MobileServices.Core.js',
'src/Transports/*.js',
'src/LoginUis/*.js',
'src/Utilities/PostMessageExchange.js',
'src/Utilities/Promises.js'
],
winjs: [
'src/Push/Push.WinJS.js',
'src/LoginUis/WebAuthBroker.js',
'src/Platforms/Platform.WinJS.js',
],
node: [
'src/Internals/NodeExports.js',
],
Internals: [
'src/Internals/InternalsVisible.js',
],
Intellisense: [
'src/Internals/DevIntellisense.js',
],
},
jshint: {
all: ['Gruntfile.js', 'src/**/*.js', '!src/External/**/*.js', '!src/Generated/*.js', 'test/**/*.js', '!test/**/bin/**', '!**/MobileServices.*.js']
},
concat: {
options: {
stripBanners: true,
banner: header,
process: wrapModule,
footer: footer
},
resources: {
options: {
banner: '\n\t$__modules__.Resources = { };\n\n',
process: wrapResourceFile,
footer: ''
},
src: ['<%= files.resources %>'],
dest: 'src/Generated/Resources.js'
},
web: {
src: ['src/Require.js', 'src/Generated/Resources.js', '<%= files.core %>', '<%= files.web %>'],
dest: 'src/Generated/MobileServices.Web.js'
},
webinternals: {
options: {
footer: '\n\trequire(\'InternalsVisible\');' + footer
},
src: ['src/Require.js', 'src/Generated/Resources.js', '<%= files.Internals %>', '<%= files.core %>', '<%= files.web %>'],
dest: 'src/Generated/MobileServices.Web.Internals.js'
},
winjs: {
src: ['src/Require.js', 'src/Generated/Resources.js', '<%= files.core %>', '<%= files.winjs %>'],
dest: 'src/Generated/MobileServices.js'
},
winjsinternals: {
options: {
footer: '\n\trequire(\'InternalsVisible\');' + footer
},
src: ['src/Require.js', 'src/Generated/Resources.js', '<%= files.Internals %>', '<%= files.core %>', '<%= files.winjs %>'],
dest: 'src/Generated/MobileServices.Internals.js'
},
Intellisense: {
options: {
footer: '\n\trequire(\'DevIntellisense\');' + footer
},
src: ['src/Require.js', '<%= files.core %>', '<%= files.winjs %>', '<%= files.Intellisense %>'],
dest: 'src/Generated/MobileServices.DevIntellisense.js'
}
},
uglify: {
options: {
banner: '//! Copyright (c) Microsoft Corporation. All rights reserved. <%= pkg.name %> v<%= pkg.version %>\n',
mangle: false
},
web: {
src: 'src/Generated/MobileServices.Web.js',
dest: 'src/Generated/MobileServices.Web.min.js'
},
winjs: {
src: 'src/Generated/MobileServices.js',
dest: 'src/Generated/MobileServices.min.js'
}
}
});
// Load the plugin that provides the "uglify" task.
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-concat');
// Default task(s).
grunt.registerTask('default', ['jshint', 'concat', 'uglify']);
};
var header = '// ----------------------------------------------------------------------------\n' +
'// Copyright (c) Microsoft Corporation. All rights reserved\n' +
'// <%= pkg.name %> - v<%= pkg.version %>\n' +
'// ----------------------------------------------------------------------------\n' +
'\n' +
'(function (global) {\n' +
'\tvar $__fileVersion__ = \'<%= pkg.version %>\';\n',
footer = '\n\trequire(\'MobileServiceClient\');\n' +
'})(this || exports);';
function wrapModule(src, filepath) {
///
/// Takes a file, and if it should be a module, wraps the code in a module block
///
///
/// Source code of a module file
///
///
/// Sile path of the module (i.e. src/MobileServicesClient.js)
///
var lastSlash = filepath.lastIndexOf('/'),
name = filepath.substr(lastSlash + 1);
name = name.substring(0, name.indexOf('.'));
if (name == 'Require' || name == 'Resources') {
return src;
}
var newSrc = src.replace(/\/\/\/\s<[\w\s=":\\().]+\/>\n/g, '');
newSrc = '\t\t' + newSrc.replace(/\n/g, '\n\t\t');
return '\n\t$__modules__.' + name + ' = function (exports) {\n' + newSrc + '\n\t};';
}
function wrapResourceFile(src, filepath) {
///
/// Takes a resjson file and places it into a module level resources array
/// with the index corresponding to the language identifier in the file path
///
///
/// Source code of a module file
///
///
/// File path of the resjson (i.e. src/Strings/en-US/Resources.resjson)
/// The file name must be in format of //Resources.resjson
///
var language = filepath.replace('src/Strings/', '').replace('/Resources.resjson', ''),
newSrc = src.replace(/\n/g, '\n\t\t');
return '\t$__modules__.Resources[\'' + language + '\'] = ' + newSrc + ';';
}
================================================
FILE: sdk/Javascript/Microsoft.WindowsAzure.Mobile.JS.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.30723.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.WindowsAzure.Mobile.JS", "src\Microsoft.WindowsAzure.Mobile.JS.csproj", "{0D39CF6F-4884-4D43-8744-2CEB723629C8}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{2BDD39FE-2E9F-4B97-8173-02037CF765AA}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{F52A1420-8C01-42ED-8EF2-71F83EE49A87}"
EndProject
Project("{262852C6-CD72-467D-83FE-5EEB1973A190}") = "Microsoft.WindowsAzure.Mobile.WinJS.Test", "test\winJS\Microsoft.WindowsAzure.Mobile.WinJS.Test.jsproj", "{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}"
ProjectSection(ProjectDependencies) = postProject
{0D39CF6F-4884-4D43-8744-2CEB723629C8} = {0D39CF6F-4884-4D43-8744-2CEB723629C8}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.WindowsAzure.Mobile.WinJS.TestFramework", "test\framework\Microsoft.WindowsAzure.Mobile.WinJS.TestFramework.csproj", "{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{8F22488F-603B-4BA2-9AA0-DBC7D4487978}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.WindowsAzure.Mobile.JSBuild", "tools\JSBuild\Microsoft.WindowsAzure.Mobile.JSBuild.csproj", "{FFD91CC6-07FF-4D69-A064-2A911E2B4087}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Azure.Zumo.Web.Test", "test\web\Microsoft.Azure.Zumo.Web.Test.csproj", "{5AA504E2-10A2-4179-9645-47E5CF857DDF}"
ProjectSection(ProjectDependencies) = postProject
{0D39CF6F-4884-4D43-8744-2CEB723629C8} = {0D39CF6F-4884-4D43-8744-2CEB723629C8}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B7E1D498-5891-43F0-80A6-6DE18515433C}"
ProjectSection(SolutionItems) = preProject
gruntfile.js = gruntfile.js
package.json = package.json
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
BuildTools|Any CPU = BuildTools|Any CPU
BuildTools|ARM = BuildTools|ARM
BuildTools|x64 = BuildTools|x64
BuildTools|x86 = BuildTools|x86
Debug|Any CPU = Debug|Any CPU
Debug|ARM = Debug|ARM
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|ARM = Release|ARM
Release|x64 = Release|x64
Release|x86 = Release|x86
Signed|Any CPU = Signed|Any CPU
Signed|ARM = Signed|ARM
Signed|x64 = Signed|x64
Signed|x86 = Signed|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.BuildTools|Any CPU.ActiveCfg = BuildTools|Any CPU
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.BuildTools|ARM.ActiveCfg = BuildTools|ARM
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.BuildTools|ARM.Build.0 = BuildTools|ARM
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.BuildTools|x64.ActiveCfg = BuildTools|x64
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.BuildTools|x64.Build.0 = BuildTools|x64
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.BuildTools|x86.ActiveCfg = BuildTools|x86
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.BuildTools|x86.Build.0 = BuildTools|x86
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Debug|ARM.ActiveCfg = Debug|ARM
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Debug|ARM.Build.0 = Debug|ARM
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Debug|x64.ActiveCfg = Debug|x64
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Debug|x64.Build.0 = Debug|x64
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Debug|x86.ActiveCfg = Debug|x86
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Debug|x86.Build.0 = Debug|x86
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Release|Any CPU.Build.0 = Release|Any CPU
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Release|ARM.ActiveCfg = Release|ARM
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Release|ARM.Build.0 = Release|ARM
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Release|x64.ActiveCfg = Release|x64
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Release|x64.Build.0 = Release|x64
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Release|x86.ActiveCfg = Release|x86
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Release|x86.Build.0 = Release|x86
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Signed|Any CPU.ActiveCfg = Release|Any CPU
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Signed|Any CPU.Build.0 = Release|Any CPU
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Signed|ARM.ActiveCfg = Release|ARM
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Signed|ARM.Build.0 = Release|ARM
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Signed|x64.ActiveCfg = Release|x64
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Signed|x64.Build.0 = Release|x64
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Signed|x86.ActiveCfg = Release|x86
{0D39CF6F-4884-4D43-8744-2CEB723629C8}.Signed|x86.Build.0 = Release|x86
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.BuildTools|Any CPU.ActiveCfg = BuildTools|Any CPU
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.BuildTools|ARM.ActiveCfg = BuildTools|ARM
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.BuildTools|ARM.Build.0 = BuildTools|ARM
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.BuildTools|ARM.Deploy.0 = BuildTools|ARM
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.BuildTools|x64.ActiveCfg = BuildTools|x64
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.BuildTools|x64.Build.0 = BuildTools|x64
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.BuildTools|x64.Deploy.0 = BuildTools|x64
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.BuildTools|x86.ActiveCfg = BuildTools|x86
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.BuildTools|x86.Build.0 = BuildTools|x86
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.BuildTools|x86.Deploy.0 = BuildTools|x86
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Debug|ARM.ActiveCfg = Debug|ARM
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Debug|ARM.Build.0 = Debug|ARM
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Debug|ARM.Deploy.0 = Debug|ARM
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Debug|x64.ActiveCfg = Debug|x64
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Debug|x64.Build.0 = Debug|x64
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Debug|x64.Deploy.0 = Debug|x64
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Debug|x86.ActiveCfg = Debug|x86
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Debug|x86.Build.0 = Debug|x86
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Debug|x86.Deploy.0 = Debug|x86
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Release|Any CPU.Build.0 = Release|Any CPU
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Release|Any CPU.Deploy.0 = Release|Any CPU
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Release|ARM.ActiveCfg = Release|ARM
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Release|ARM.Build.0 = Release|ARM
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Release|ARM.Deploy.0 = Release|ARM
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Release|x64.ActiveCfg = Release|x64
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Release|x64.Build.0 = Release|x64
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Release|x64.Deploy.0 = Release|x64
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Release|x86.ActiveCfg = Release|x86
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Release|x86.Build.0 = Release|x86
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Release|x86.Deploy.0 = Release|x86
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Signed|Any CPU.ActiveCfg = Debug|Any CPU
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Signed|Any CPU.Build.0 = Debug|Any CPU
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Signed|Any CPU.Deploy.0 = Debug|Any CPU
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Signed|ARM.ActiveCfg = Release|ARM
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Signed|ARM.Build.0 = Release|ARM
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Signed|ARM.Deploy.0 = Release|ARM
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Signed|x64.ActiveCfg = Release|x64
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Signed|x64.Build.0 = Release|x64
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Signed|x64.Deploy.0 = Release|x64
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Signed|x86.ActiveCfg = Release|x86
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Signed|x86.Build.0 = Release|x86
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C}.Signed|x86.Deploy.0 = Release|x86
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.BuildTools|Any CPU.ActiveCfg = BuildTools|Any CPU
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.BuildTools|ARM.ActiveCfg = BuildTools|ARM
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.BuildTools|ARM.Build.0 = BuildTools|ARM
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.BuildTools|x64.ActiveCfg = BuildTools|x64
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.BuildTools|x64.Build.0 = BuildTools|x64
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.BuildTools|x86.ActiveCfg = BuildTools|x86
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.BuildTools|x86.Build.0 = BuildTools|x86
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Debug|ARM.ActiveCfg = Debug|ARM
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Debug|ARM.Build.0 = Debug|ARM
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Debug|x64.ActiveCfg = Debug|x64
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Debug|x64.Build.0 = Debug|x64
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Debug|x86.ActiveCfg = Debug|x86
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Debug|x86.Build.0 = Debug|x86
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Release|Any CPU.Build.0 = Release|Any CPU
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Release|ARM.ActiveCfg = Release|ARM
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Release|ARM.Build.0 = Release|ARM
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Release|x64.ActiveCfg = Release|x64
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Release|x64.Build.0 = Release|x64
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Release|x86.ActiveCfg = Release|x86
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Release|x86.Build.0 = Release|x86
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Signed|Any CPU.ActiveCfg = Signed|Any CPU
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Signed|Any CPU.Build.0 = Signed|Any CPU
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Signed|ARM.ActiveCfg = Signed|ARM
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Signed|ARM.Build.0 = Signed|ARM
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Signed|x64.ActiveCfg = Signed|x64
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Signed|x64.Build.0 = Signed|x64
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Signed|x86.ActiveCfg = Signed|x86
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE}.Signed|x86.Build.0 = Signed|x86
{FFD91CC6-07FF-4D69-A064-2A911E2B4087}.BuildTools|Any CPU.ActiveCfg = BuildTools|Any CPU
{FFD91CC6-07FF-4D69-A064-2A911E2B4087}.BuildTools|Any CPU.Build.0 = BuildTools|Any CPU
{FFD91CC6-07FF-4D69-A064-2A911E2B4087}.BuildTools|ARM.ActiveCfg = BuildTools|Any CPU
{FFD91CC6-07FF-4D69-A064-2A911E2B4087}.BuildTools|x64.ActiveCfg = BuildTools|Any CPU
{FFD91CC6-07FF-4D69-A064-2A911E2B4087}.BuildTools|x86.ActiveCfg = BuildTools|Any CPU
{FFD91CC6-07FF-4D69-A064-2A911E2B4087}.Debug|Any CPU.ActiveCfg = BuildTools|Any CPU
{FFD91CC6-07FF-4D69-A064-2A911E2B4087}.Debug|ARM.ActiveCfg = BuildTools|Any CPU
{FFD91CC6-07FF-4D69-A064-2A911E2B4087}.Debug|x64.ActiveCfg = BuildTools|Any CPU
{FFD91CC6-07FF-4D69-A064-2A911E2B4087}.Debug|x86.ActiveCfg = BuildTools|Any CPU
{FFD91CC6-07FF-4D69-A064-2A911E2B4087}.Release|Any CPU.ActiveCfg = BuildTools|Any CPU
{FFD91CC6-07FF-4D69-A064-2A911E2B4087}.Release|Any CPU.Build.0 = BuildTools|Any CPU
{FFD91CC6-07FF-4D69-A064-2A911E2B4087}.Release|ARM.ActiveCfg = BuildTools|Any CPU
{FFD91CC6-07FF-4D69-A064-2A911E2B4087}.Release|x64.ActiveCfg = BuildTools|Any CPU
{FFD91CC6-07FF-4D69-A064-2A911E2B4087}.Release|x86.ActiveCfg = BuildTools|Any CPU
{FFD91CC6-07FF-4D69-A064-2A911E2B4087}.Signed|Any CPU.ActiveCfg = BuildTools|Any CPU
{FFD91CC6-07FF-4D69-A064-2A911E2B4087}.Signed|Any CPU.Build.0 = BuildTools|Any CPU
{FFD91CC6-07FF-4D69-A064-2A911E2B4087}.Signed|ARM.ActiveCfg = BuildTools|Any CPU
{FFD91CC6-07FF-4D69-A064-2A911E2B4087}.Signed|x64.ActiveCfg = BuildTools|Any CPU
{FFD91CC6-07FF-4D69-A064-2A911E2B4087}.Signed|x86.ActiveCfg = BuildTools|Any CPU
{5AA504E2-10A2-4179-9645-47E5CF857DDF}.BuildTools|Any CPU.ActiveCfg = BuildTools|Any CPU
{5AA504E2-10A2-4179-9645-47E5CF857DDF}.BuildTools|ARM.ActiveCfg = BuildTools|Any CPU
{5AA504E2-10A2-4179-9645-47E5CF857DDF}.BuildTools|x64.ActiveCfg = BuildTools|Any CPU
{5AA504E2-10A2-4179-9645-47E5CF857DDF}.BuildTools|x86.ActiveCfg = BuildTools|Any CPU
{5AA504E2-10A2-4179-9645-47E5CF857DDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5AA504E2-10A2-4179-9645-47E5CF857DDF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5AA504E2-10A2-4179-9645-47E5CF857DDF}.Debug|ARM.ActiveCfg = Debug|Any CPU
{5AA504E2-10A2-4179-9645-47E5CF857DDF}.Debug|x64.ActiveCfg = Debug|Any CPU
{5AA504E2-10A2-4179-9645-47E5CF857DDF}.Debug|x86.ActiveCfg = Debug|Any CPU
{5AA504E2-10A2-4179-9645-47E5CF857DDF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5AA504E2-10A2-4179-9645-47E5CF857DDF}.Release|Any CPU.Build.0 = Release|Any CPU
{5AA504E2-10A2-4179-9645-47E5CF857DDF}.Release|ARM.ActiveCfg = Release|Any CPU
{5AA504E2-10A2-4179-9645-47E5CF857DDF}.Release|x64.ActiveCfg = Release|Any CPU
{5AA504E2-10A2-4179-9645-47E5CF857DDF}.Release|x86.ActiveCfg = Release|Any CPU
{5AA504E2-10A2-4179-9645-47E5CF857DDF}.Signed|Any CPU.ActiveCfg = Release|Any CPU
{5AA504E2-10A2-4179-9645-47E5CF857DDF}.Signed|Any CPU.Build.0 = Release|Any CPU
{5AA504E2-10A2-4179-9645-47E5CF857DDF}.Signed|ARM.ActiveCfg = Release|Any CPU
{5AA504E2-10A2-4179-9645-47E5CF857DDF}.Signed|x64.ActiveCfg = Release|Any CPU
{5AA504E2-10A2-4179-9645-47E5CF857DDF}.Signed|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{0D39CF6F-4884-4D43-8744-2CEB723629C8} = {2BDD39FE-2E9F-4B97-8173-02037CF765AA}
{96B18D27-DFF3-47A2-835B-EF1E6AF1A39C} = {F52A1420-8C01-42ED-8EF2-71F83EE49A87}
{6445515D-9E58-4812-BAD6-BC81DAF1C0EE} = {F52A1420-8C01-42ED-8EF2-71F83EE49A87}
{FFD91CC6-07FF-4D69-A064-2A911E2B4087} = {8F22488F-603B-4BA2-9AA0-DBC7D4487978}
{5AA504E2-10A2-4179-9645-47E5CF857DDF} = {F52A1420-8C01-42ED-8EF2-71F83EE49A87}
EndGlobalSection
EndGlobal
================================================
FILE: sdk/Javascript/package.json
================================================
{
"name": "AzureMobileServices",
"version": "1.2.8",
"devDependencies": {
"grunt": "~0.4.5",
"grunt-contrib-jshint": "~0.10.0",
"grunt-contrib-nodeunit": "~0.4.1",
"grunt-contrib-uglify": "~0.6.0",
"grunt-contrib-concat": "~0.5.0"
}
}
================================================
FILE: sdk/Javascript/src/Generated/.gitignore
================================================
*
!.gitignore
================================================
FILE: sdk/Javascript/src/Internals/DevIntellisense.js
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
// The following declarations will let Visual Studio provide cross-module
// Intellisense by defining free variables provided by the module system as
// globals that it can find. Visual Studio's JavaScript Intellisense engine
// will actually evaluate code on a background thread, so when your module
// calls require('foo'), VS actually runs the real require code (since we make
// it visible here) and will provide Intellisense for all of foo's exports.
global.exports = {};
global.require = require;
================================================
FILE: sdk/Javascript/src/Internals/InternalsVisible.js
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
// Walk all of the registered modules and make all of their exports publicly
// available for unit testing. This relies on both the global and $__modules__
// free variables exposed via our module system.
// Cache all of the module definition functions before any of the modules have
// been require-d. This allows us to reset the modules by reevaluating all of
// the definition functions.
var moduleCache = {};
var moduleName = null;
for (moduleName in $__modules__) {
moduleCache[moduleName] = $__modules__[moduleName];
}
// Expose all of the exports for each module
exposeModules();
function exposeModules() {
///
/// Expose all of the exports for a module as a global member so they can
/// be easily accessed for testing.
///
///
/// Note that all modules will be require-d to gain access to their
/// exported members.
///
var moduleName = null;
for (moduleName in $__modules__) {
// We need to require the module which will force all of its exports to
// be defined (or do nothing if they've already been require-d).
require(moduleName);
// Declare a new global variable with the module's names that will
// contain all of its exports.
global[moduleName] = $__modules__[moduleName];
}
}
global.resetModules = function () {
///
/// Reset the modules by reevaluating the functions that provide their
/// exports.
///
// Reset $__modules__ to contain the original functions
var moduleName = null;
for (moduleName in $__modules__) {
$__modules__[moduleName] = moduleCache[moduleName];
}
// Re-require all of the modules which will reevaluate their functions
exposeModules();
};
================================================
FILE: sdk/Javascript/src/Internals/NodeExports.js
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
// The server-side node runtime wants to provide the same query syntax and we
// want to reuse as much code as possible. This will bundle up the entire
// library and add a single node.js export that translates queries into OData.
global.Query = require('Query').Query;
================================================
FILE: sdk/Javascript/src/LoginUis/BrowserPopup.js
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
var PostMessageExchange = require('PostMessageExchange');
exports.supportsCurrentRuntime = function () {
///
/// Determines whether or not this login UI is usable in the current runtime.
///
return true;
};
exports.login = function (startUri, endUri, callback) {
///
/// Displays the login UI and calls back on completion
///
// Tell the runtime which form of completion signal we are looking for,
// and which origin should be allowed to receive the result (note that this
// is validated against whitelist on the server; we are only supplying this
// origin to indicate *which* of the whitelisted origins to use).
var completionOrigin = PostMessageExchange.getOriginRoot(window.location.href),
runtimeOrigin = PostMessageExchange.getOriginRoot(startUri),
// IE does not support popup->opener postMessage calls, so we have to
// route the message via an iframe
useIntermediateIframe = window.navigator.userAgent.indexOf("MSIE") >= 0 || window.navigator.userAgent.indexOf("Trident") >= 0,
intermediateIframe = useIntermediateIframe && createIntermediateIframeForLogin(runtimeOrigin, completionOrigin),
completionType = useIntermediateIframe ? "iframe" : "postMessage";
startUri += startUri.indexOf('?') == -1 ? '?' : '&';
startUri += "completion_type=" + completionType + "&completion_origin=" + encodeURIComponent(completionOrigin);
// Browsers don't allow postMessage to a file:// URL (except by setting origin to "*", which is unacceptable)
// so abort the process early with an explanation in that case.
if (!(completionOrigin && (completionOrigin.indexOf("http:") === 0 || completionOrigin.indexOf("https:") === 0))) {
var error = "Login is only supported from http:// or https:// URLs. Please host your page in a web server.";
callback(error, null);
return;
}
var loginWindow = window.open(startUri, "_blank", "location=no"),
complete = function(errorValue, oauthValue) {
// Clean up event handlers, windows, frames, ...
window.clearInterval(checkForWindowClosedInterval);
loginWindow.close();
if (window.removeEventListener) {
window.removeEventListener("message", handlePostMessage);
} else {
// For IE8
window.detachEvent("onmessage", handlePostMessage);
}
if (intermediateIframe) {
intermediateIframe.parentNode.removeChild(intermediateIframe);
}
// Finally, notify the caller
callback(errorValue, oauthValue);
},
handlePostMessage = function(evt) {
// Validate source
var expectedSource = useIntermediateIframe ? intermediateIframe.contentWindow : loginWindow;
if (evt.source !== expectedSource) {
return;
}
// Parse message
var envelope;
try {
envelope = JSON.parse(evt.data);
} catch(ex) {
// Not JSON - it's not for us. Ignore it and keep waiting for the next message.
return;
}
// Process message only if it's for us
if (envelope && envelope.type === "LoginCompleted" && (envelope.oauth || envelope.error)) {
complete(envelope.error, envelope.oauth);
}
},
checkForWindowClosedInterval = window.setInterval(function() {
// We can't directly catch any "onclose" event from the popup because it's usually on a different
// origin, but in all the mainstream browsers we can poll for changes to its "closed" property
if (loginWindow && loginWindow.closed === true) {
complete("canceled", null);
}
}, 250);
if (window.addEventListener) {
window.addEventListener("message", handlePostMessage, false);
} else {
// For IE8
window.attachEvent("onmessage", handlePostMessage);
}
// Permit cancellation, e.g., if the app tries to login again while the popup is still open
return {
cancelCallback: function () {
complete("canceled", null);
return true; // Affirm that it was cancelled
}
};
};
function createIntermediateIframeForLogin(runtimeOrigin, completionOrigin) {
var frame = document.createElement("iframe");
frame.name = "zumo-login-receiver"; // loginviaiframe.html specifically looks for this name
frame.src = runtimeOrigin +
"/crossdomain/loginreceiver?completion_origin=" + encodeURIComponent(completionOrigin);
frame.setAttribute("width", 0);
frame.setAttribute("height", 0);
frame.style.display = "none";
document.body.appendChild(frame);
return frame;
}
================================================
FILE: sdk/Javascript/src/LoginUis/CordovaPopup.js
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
// Note: Cordova is PhoneGap.
// This login UI implementation uses the InAppBrowser plugin,
// to install the plugin use the following command
// cordova plugin add org.apache.cordova.inappbrowser
var requiredCordovaVersion = { major: 3, minor: 0 };
exports.supportsCurrentRuntime = function () {
///
/// Determines whether or not this login UI is usable in the current runtime.
///
// When running application inside of Ripple emulator, InAppBrowser functionality is not supported.
// We should use Browser popup login method instead.
return !!currentCordovaVersion() && !isRunUnderRippleEmulator();
};
exports.login = function (startUri, endUri, callback) {
///
/// Displays the login UI and calls back on completion
///
// Ensure it's a sufficiently new version of Cordova, and if not fail synchronously so that
// the error message will show up in the browser console.
var foundCordovaVersion = currentCordovaVersion(),
message;
if (!isSupportedCordovaVersion(foundCordovaVersion)) {
message = "Not a supported version of Cordova. Detected: " + foundCordovaVersion +
". Required: " + requiredCordovaVersion.major + "." + requiredCordovaVersion.minor;
throw new Error(message);
}
if (!hasInAppBrowser) {
message = 'A required plugin: "org.apache.cordova.inappbrowser" was not detected.';
throw new Error(message);
}
// Initially we show a page with a spinner. This stays on screen until the login form has loaded.
var redirectionScript = "",
startPage = "data:text/html," + encodeURIComponent(getSpinnerMarkup() + redirectionScript);
// iOS inAppBrowser issue requires this wrapping
setTimeout(function () {
var loginWindow = window.open(startPage, "_blank", "location=no"),
flowHasFinished = false,
loadEventHandler = function (evt) {
if (!flowHasFinished && evt.url.indexOf(endUri) === 0) {
flowHasFinished = true;
setTimeout(function () {
loginWindow.close();
}, 500);
var result = parseOAuthResultFromDoneUrl(evt.url);
callback(result.error, result.oAuthToken);
}
};
// Ideally we'd just use loadstart because it happens earlier, but it randomly skips
// requests on iOS, so we have to listen for loadstop as well (which is reliable).
loginWindow.addEventListener('loadstart', loadEventHandler);
loginWindow.addEventListener('loadstop', loadEventHandler);
loginWindow.addEventListener('exit', function (evt) {
if (!flowHasFinished) {
flowHasFinished = true;
callback("UserCancelled", null);
}
});
}, 500);
};
function isRunUnderRippleEmulator () {
// Returns true when application runs under Ripple emulator
return window.parent && !!window.parent.ripple;
}
function currentCordovaVersion() {
// If running inside Cordova, returns a string similar to "3.5.0". Otherwise, returns a falsey value.
// Note: We can only detect Cordova after its deviceready event has fired, so don't call login until then.
return window.cordova && window.cordova.version;
}
function isSupportedCordovaVersion(version) {
var versionParts = currentCordovaVersion().match(/^(\d+).(\d+)./);
if (versionParts) {
var major = Number(versionParts[1]),
minor = Number(versionParts[2]),
required = requiredCordovaVersion;
return (major > required.major) ||
(major === required.major && minor >= required.minor);
}
return false;
}
function hasInAppBrowser() {
return !window.open;
}
function parseOAuthResultFromDoneUrl(url) {
var successMessage = extractMessageFromUrl(url, "#token="),
errorMessage = extractMessageFromUrl(url, "#error=");
return {
oAuthToken: successMessage ? JSON.parse(successMessage) : null,
error: errorMessage
};
}
function extractMessageFromUrl(url, separator) {
var pos = url.indexOf(separator);
return pos < 0 ? null : decodeURIComponent(url.substring(pos + separator.length));
}
function getSpinnerMarkup() {
// The default InAppBrowser experience isn't ideal, as it just shows the user a blank white screen
// until the login form appears. This might take 10+ seconds during which it looks broken.
// Also on iOS it's possible for the InAppBrowser to initially show the results of the *previous*
// login flow if the InAppBrowser was dismissed before completion, which is totally undesirable.
// To fix both of these problems, we display a simple "spinner" graphic via a data: URL until
// the current login screen has loaded. We generate the spinner via CSS rather than referencing
// an animated GIF just because this makes the client library smaller overall.
var vendorPrefix = "webkitTransform" in document.documentElement.style ? "-webkit-" : "",
numSpokes = 12,
spokesMarkup = "";
for (var i = 0; i < numSpokes; i++) {
spokesMarkup += "";
}
return [
"",
"",
"
" + spokesMarkup + "
",
"",
""
].join("").replace(/-prefix-/g, vendorPrefix);
}
================================================
FILE: sdk/Javascript/src/LoginUis/WebAuthBroker.js
================================================
exports.supportsCurrentRuntime = function () {
///
/// Determines whether or not this login UI is usable in the current runtime.
///
return isWebAuthBrokerAvailable();
};
exports.login = function (startUri, endUri, callback) {
///
/// Displays the login UI and calls back on completion
///
// Define shortcuts for namespaces
var windowsWebAuthBroker = Windows.Security.Authentication.Web.WebAuthenticationBroker;
var noneWebAuthOptions = Windows.Security.Authentication.Web.WebAuthenticationOptions.none;
var successWebAuthStatus = Windows.Security.Authentication.Web.WebAuthenticationStatus.success;
var activationKindWebAuthContinuation = Windows.ApplicationModel.Activation.ActivationKind.webAuthenticationBrokerContinuation;
var webAuthBrokerSuccessCallback = null;
var webAuthBrokerErrorCallback = null;
var webAuthBrokerContinuationCallback = null;
// define callbacks for WebAuthenticationBroker
webAuthBrokerSuccessCallback = function (result) {
var error = null;
var token = null;
if (result.responseStatus !== successWebAuthStatus) {
error = result;
}
else {
var callbackEndUri = result.responseData;
var tokenAsJson = null;
var i = callbackEndUri.indexOf('#token=');
if (i > 0) {
tokenAsJson = decodeURIComponent(callbackEndUri.substring(i + 7));
}
else {
i = callbackEndUri.indexOf('#error=');
if (i > 0) {
error = decodeURIComponent(callbackEndUri.substring(i + 7));
}
}
if (tokenAsJson !== null) {
try {
token = JSON.parse(tokenAsJson);
}
catch (e) {
error = e;
}
}
}
callback(error, token);
};
webAuthBrokerErrorCallback = function (error) {
callback(error, null);
};
// Continuation callback is used when we're running on WindowsPhone which uses
// AuthenticateAndContinue method instead of AuthenticateAsync, which uses different async model
// Continuation callback need to be assigned to Application's 'activated' event.
webAuthBrokerContinuationCallback = function (activationArgs) {
if (activationArgs.detail.kind === activationKindWebAuthContinuation) {
var result = activationArgs.detail.webAuthenticationResult;
if (result.responseStatus == successWebAuthStatus) {
webAuthBrokerSuccessCallback(result);
} else {
webAuthBrokerErrorCallback(result);
}
WinJS.Application.removeEventListener('activated', webAuthBrokerContinuationCallback);
}
};
if (endUri) {
var windowsStartUri = new Windows.Foundation.Uri(startUri);
var windowsEndUri = new Windows.Foundation.Uri(endUri);
// If authenticateAndContinue method is available, we should use it instead of authenticateAsync
if (windowsWebAuthBroker.authenticateAndContinue) {
WinJS.Application.addEventListener('activated', webAuthBrokerContinuationCallback, true);
windowsWebAuthBroker.authenticateAndContinue(windowsStartUri, windowsEndUri);
} else {
windowsWebAuthBroker.authenticateAsync(noneWebAuthOptions, windowsStartUri, windowsEndUri)
.done(webAuthBrokerSuccessCallback, webAuthBrokerErrorCallback);
}
} else {
// If no endURI was given, then we'll use the single sign-on overload of the
// windowsWebAuthBroker. Single sign-on requires that the application's Package SID
// be registered with the Microsoft Azure Mobile Service, but it provides a better
// experience as HTTP cookies are supported so that users do not have to
// login in everytime the application is launched.
var redirectUri = windowsWebAuthBroker.getCurrentApplicationCallbackUri().absoluteUri;
var startUriWithRedirect = startUri + "?sso_end_uri=" + encodeURIComponent(redirectUri);
var windowsStartUriWithRedirect = new Windows.Foundation.Uri(startUriWithRedirect);
// If authenticateAndContinue method is available, we should use it instead of authenticateAsync
if (windowsWebAuthBroker.authenticateAndContinue) {
WinJS.Application.addEventListener('activated', webAuthBrokerContinuationCallback, true);
windowsWebAuthBroker.authenticateAndContinue(windowsStartUriWithRedirect);
} else {
windowsWebAuthBroker.authenticateAsync(noneWebAuthOptions, windowsStartUriWithRedirect)
.done(webAuthBrokerSuccessCallback, webAuthBrokerErrorCallback);
}
}
};
function isWebAuthBrokerAvailable() {
// If running on windows8/8.1 or Windows Phone returns true, otherwise false
return !!(window.Windows &&
window.Windows.Security &&
window.Windows.Security.Authentication &&
window.Windows.Security.Authentication.Web &&
window.Windows.Security.Authentication.Web.WebAuthenticationBroker);
}
================================================
FILE: sdk/Javascript/src/Microsoft.WindowsAzure.Mobile.JS.csproj
================================================
$(MSBuildProjectDirectory)\..\tools$(MSBuildProgramFiles32)\Windows Kits\8.0\bin\x64\makepri.exe..\..\Tools\makepri.exev4.5DebugAnyCPU8.0.307032.0{0D39CF6F-4884-4D43-8744-2CEB723629C8}LibraryPropertiesMicrosoft.WindowsAzure.Mobile.JSMicrosoft.WindowsAzure.Mobile.JSen-US512{BC8A1FFA-BEE3-4634-8014-F334798102B3};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}truefullfalsebin\Debug\DEBUG;TRACE;NETFX_COREprompt4false..\..\tools\Strict.rulesettruepdbonlytruebin\Release\TRACE;NETFX_COREprompt4truebin\ARM\Debug\DEBUG;TRACE;NETFX_CORE;2008fullARMfalsepromptExpressRules.rulesettruebin\ARM\Release\TRACE;NETFX_COREtrue;2008pdbonlyARMfalsepromptExpressRules.rulesettruetruebin\x64\Debug\DEBUG;TRACE;NETFX_CORE;2008fullx64falsepromptExpressRules.rulesettruebin\x64\Release\TRACE;NETFX_COREtrue;2008pdbonlyx64falsepromptExpressRules.rulesettruetruebin\x86\Debug\DEBUG;TRACE;NETFX_CORE;2008fullx86falsepromptExpressRules.rulesettruebin\x86\Release\TRACE;NETFX_COREtrue;2008pdbonlyx86falsepromptExpressRules.rulesettruetruebin\BuildTools\DEBUG;TRACE;NETFX_COREtruefullAnyCPUfalseprompt..\..\tools\Strict.rulesettruebin\ARM\BuildTools\DEBUG;TRACE;NETFX_CORE;2008truefullARMfalsepromptExpressRules.rulesettruetruebin\x64\BuildTools\DEBUG;TRACE;NETFX_CORE;2008truefullx64falsepromptExpressRules.rulesettruetruebin\x86\BuildTools\DEBUG;TRACE;NETFX_CORE;2008truefullx86falsepromptExpressRules.rulesettrue
$(BuildDependsOn);
CreatePriFile;
================================================
FILE: sdk/Javascript/src/MobileServiceClient.js
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
///
///
///
var _ = require('Extensions');
var Validate = require('Validate');
var Platform = require('Platform');
var MobileServiceTable = require('MobileServiceTable').MobileServiceTable;
var MobileServiceLogin = require('MobileServiceLogin').MobileServiceLogin;
var Push;
try {
Push = require('Push').Push;
} catch (e) { }
var _zumoFeatures = {
JsonApiCall: "AJ", // Custom API call, where the request body is serialized as JSON
GenericApiCall: "AG", // Custom API call, where the request body is sent 'as-is'
AdditionalQueryParameters: "QS", // Table or API call, where the caller passes additional query string parameters
OptimisticConcurrency: "OC", // Table update / delete call, using Optimistic Concurrency (If-Match headers)
TableRefreshCall: "RF", // Refresh table call
TableReadRaw: "TR", // Table reads where the caller uses a raw query string to determine the items to be returned
TableReadQuery: "TQ", // Table reads where the caller uses a function / query OM to determine the items to be returned
};
var _zumoFeaturesHeaderName = "X-ZUMO-FEATURES";
function MobileServiceClient(applicationUrl, applicationKey) {
///
/// Initializes a new instance of the MobileServiceClient class.
///
///
/// The URL to the Mobile Services application.
///
///
/// The Mobile Service application's key.
///
Validate.isString(applicationUrl, 'applicationUrl');
Validate.notNullOrEmpty(applicationUrl, 'applicationUrl');
Validate.isString(applicationKey, 'applicationKey');
this.applicationUrl = applicationUrl;
this.applicationKey = applicationKey || null;
var sdkInfo = Platform.getSdkInfo();
var osInfo = Platform.getOperatingSystemInfo();
var sdkVersion = sdkInfo.fileVersion.split(".").slice(0, 2).join(".");
this.version = "ZUMO/" + sdkVersion + " (lang=" + sdkInfo.language + "; " +
"os=" + osInfo.name + "; " +
"os_version=" + osInfo.version + "; " +
"arch=" + osInfo.architecture + "; " +
"version=" + sdkInfo.fileVersion + ")";
this.currentUser = null;
this._serviceFilter = null;
this._login = new MobileServiceLogin(this);
this.getTable = function (tableName) {
///
/// Gets a reference to a table and its data operations.
///
/// The name of the table.
/// A reference to the table.
Validate.isString(tableName, 'tableName');
Validate.notNullOrEmpty(tableName, 'tableName');
return new MobileServiceTable(tableName, this);
};
if (Push) {
this.push = new Push(this);
}
}
// Export the MobileServiceClient class
exports.MobileServiceClient = MobileServiceClient;
// Define the MobileServiceClient in a namespace (note: this has global effects
// unless the platform we're using chooses to ignore it because exports are
// good enough).
Platform.addToMobileServicesClientNamespace({ MobileServiceClient: MobileServiceClient });
MobileServiceClient.prototype.withFilter = function (serviceFilter) {
///
/// Create a new MobileServiceClient with a filter used to process all
/// of its HTTP requests and responses.
///
///
/// The filter to use on the service. The signature of a serviceFilter is
/// function(request, next, callback)
/// where
/// next := function(request, callback)
/// callback := function(error, response)
///
///
/// A new MobileServiceClient whose HTTP requests and responses will be
/// filtered as desired.
///
///
/// The Mobile Services HTTP pipeline is a chain of filters composed
/// together by giving each the next operation which it can invoke
/// (zero, one, or many times as necessary). The default continuation
/// of a brand new MobileServiceClient will just get the HTTP response
/// for the corresponding request. Here's an example of a Handle
/// implementation that will automatically retry a request that times
/// out.
/// function(req, next, callback) {
/// next(req, function(err, rsp) {
/// if (rsp.statusCode >= 400) {
/// next(req, callback);
/// } else {
/// callback(err, rsp);
/// }
/// });
/// }
/// Note that because these operations are asynchronous, this sample
/// filter could end up actually making two HTTP requests before
/// returning a response to the developer without the developer writing
/// any special code to handle the situation.
/// -
/// Filters are composed just like standard function composition. If
/// we had new MobileServiceClient().withFilter(F1).withFilter(F2)
/// .withFilter(F3), it's conceptually equivalent to saying:
/// var response = F3(F2(F1(next(request)));
///
Validate.notNull(serviceFilter, 'serviceFilter');
// Clone the current instance
var client = new MobileServiceClient(this.applicationUrl, this.applicationKey);
client.currentUser = this.currentUser;
// Chain the service filter with any existing filters
var existingFilter = this._serviceFilter;
client._serviceFilter = _.isNull(existingFilter) ?
serviceFilter :
function (req, next, callback) {
// compose existingFilter with next so it can be used as the next
// of the new serviceFilter
var composed = function (req, callback) {
existingFilter(req, next, callback);
};
serviceFilter(req, composed, callback);
};
return client;
};
MobileServiceClient.prototype._request = function (method, uriFragment, content, ignoreFilters, headers, features, callback) {
///
/// Perform a web request and include the standard Mobile Services headers.
///
///
/// The HTTP method used to request the resource.
///
///
/// URI of the resource to request (relative to the Mobile Services
/// runtime).
///
///
/// Optional content to send to the resource.
///
///
/// Optional parameter to indicate if the client filters should be ignored
/// and the request should be sent directly. Is false by default.
///
///
/// Optional request headers
///
///
/// Codes for features which are used in this request, sent to the server for telemetry.
///
///
/// Handler that will be called on the response.
///
// Account for absent optional arguments
if (_.isNull(callback) && (typeof features === 'function')) {
callback = features;
features = null;
}
if (_.isNull(callback) && (typeof headers === 'function')) {
callback = headers;
headers = null;
}
if (_.isNull(callback) && (typeof ignoreFilters === 'function')) {
callback = ignoreFilters;
ignoreFilters = false;
}
if (_.isNull(callback) && (typeof content === 'function')) {
callback = content;
content = null;
}
Validate.isString(method, 'method');
Validate.notNullOrEmpty(method, 'method');
Validate.isString(uriFragment, 'uriFragment');
Validate.notNull(uriFragment, 'uriFragment');
Validate.notNull(callback, 'callback');
// Create the absolute URI
var options = { type: method.toUpperCase() };
if (_.url.isAbsoluteUrl(uriFragment)) {
options.url = uriFragment;
} else {
options.url = _.url.combinePathSegments(this.applicationUrl, uriFragment);
}
// Set MobileServices authentication, application, User-Agent and telemetry headers
options.headers = {};
if (!_.isNull(headers)) {
_.extend(options.headers, headers);
}
options.headers["X-ZUMO-INSTALLATION-ID"] = MobileServiceClient._applicationInstallationId;
if (!_.isNullOrEmpty(this.applicationKey)) {
options.headers["X-ZUMO-APPLICATION"] = this.applicationKey;
}
if (this.currentUser && !_.isNullOrEmpty(this.currentUser.mobileServiceAuthenticationToken)) {
options.headers["X-ZUMO-AUTH"] = this.currentUser.mobileServiceAuthenticationToken;
}
if (!_.isNull(MobileServiceClient._userAgent)) {
options.headers["User-Agent"] = MobileServiceClient._userAgent;
}
if (!_.isNullOrEmpty["X-ZUMO-VERSION"]) {
options.headers["X-ZUMO-VERSION"] = this.version;
}
if (_.isNull(options.headers[_zumoFeaturesHeaderName]) && features && features.length) {
options.headers[_zumoFeaturesHeaderName] = features.join(',');
}
// Add any content as JSON
if (!_.isNull(content)) {
if (!_.isString(content)) {
options.data = _.toJson(content);
} else {
options.data = content;
}
if(!_.hasProperty(options.headers, ['Content-Type','content-type','CONTENT-TYPE','Content-type'])) {
options.headers['Content-Type'] = 'application/json';
}
} else {
// options.data must be set to null if there is no content or the xhr object
// will set the content-type to "application/text" for non-GET requests.
options.data = null;
}
// Treat any >=400 status codes as errors. Also treat the status code 0 as
// an error (which indicates a connection failure).
var handler = function (error, response) {
if (!_.isNull(error)) {
error = _.createError(error);
} else if (!_.isNull(response) && (response.status >= 400 || response.status === 0)) {
error = _.createError(null, response);
response = null;
}
callback(error, response);
};
// Make the web request
if (!_.isNull(this._serviceFilter) && !ignoreFilters) {
this._serviceFilter(options, Platform.webRequest, handler);
} else {
Platform.webRequest(options, handler);
}
};
MobileServiceClient.prototype.loginWithOptions = Platform.async(
function (provider, options, callback) {
///
/// Log a user into a Mobile Services application given a provider name with
/// given options.
///
///
/// Name of the authentication provider to use; one of 'facebook', 'twitter', 'google',
/// 'windowsazureactivedirectory' (can also use 'aad')
/// or 'microsoftaccount'.
///
///
/// Contains additional parameter information, valid values are:
/// token: provider specific object with existing OAuth token to log in with
/// useSingleSignOn: Only applies to Windows 8 clients. Will be ignored on other platforms.
/// Indicates if single sign-on should be used. Single sign-on requires that the
/// application's Package SID be registered with the Microsoft Azure Mobile Service,
/// but it provides a better experience as HTTP cookies are supported so that users
/// do not have to login in everytime the application is launched.
/// parameters: Any additional provider specific query string parameters.
///
///
/// Optional callback accepting (error, user) parameters.
///
this._login.loginWithOptions(provider, options, callback);
});
MobileServiceClient.prototype.login = Platform.async(
function (provider, token, useSingleSignOn, callback) {
///
/// Log a user into a Mobile Services application given a provider name and optional
/// authentication token.
///
///
/// Name of the authentication provider to use; one of 'facebook', 'twitter', 'google',
/// 'windowsazureactivedirectory' (can also use 'aad')
/// or 'microsoftaccount'. If no provider is specified, the 'token' parameter
/// is considered a Microsoft Account authentication token. If a provider is specified,
/// the 'token' parameter is considered a provider-specific authentication token.
///
///
/// Optional, provider specific object with existing OAuth token to log in with.
///
///
/// Only applies to Windows 8 clients. Will be ignored on other platforms.
/// Indicates if single sign-on should be used. Single sign-on requires that the
/// application's Package SID be registered with the Microsoft Azure Mobile Service,
/// but it provides a better experience as HTTP cookies are supported so that users
/// do not have to login in everytime the application is launched.
///
///
/// Optional callback accepting (error, user) parameters.
///
this._login.login(provider, token, useSingleSignOn, callback);
});
MobileServiceClient.prototype.logout = function () {
///
/// Log a user out of a Mobile Services application.
///
this.currentUser = null;
};
MobileServiceClient.prototype.invokeApi = Platform.async(
function (apiName, options, callback) {
///
/// Invokes the specified custom api and returns a response object.
///
///
/// The custom api to invoke.
///
///
/// Contains additional parameter information, valid values are:
/// body: The body of the HTTP request.
/// method: The HTTP method to use in the request, with the default being POST,
/// parameters: Any additional query string parameters,
/// headers: HTTP request headers, specified as an object.
///
///
/// Optional callback accepting (error, results) parameters.
///
Validate.isString(apiName, 'apiName');
// Account for absent optional arguments
if (_.isNull(callback)) {
if (typeof options === 'function') {
callback = options;
options = null;
}
}
Validate.notNull(callback, 'callback');
var parameters, method, body, headers;
if (!_.isNull(options)) {
parameters = options.parameters;
if (!_.isNull(parameters)) {
Validate.isValidParametersObject(options.parameters);
}
method = options.method;
body = options.body;
headers = options.headers;
}
headers = headers || {};
if (_.isNull(method)) {
method = "POST";
}
// if not specified, default to return results in JSON format
if (_.isNull(headers.accept)) {
headers.accept = 'application/json';
}
// Construct the URL
var urlFragment = _.url.combinePathSegments("api", apiName);
if (!_.isNull(parameters)) {
var queryString = _.url.getQueryString(parameters);
urlFragment = _.url.combinePathAndQuery(urlFragment, queryString);
}
var features = [];
if (!_.isNullOrEmpty(body)) {
features.push(_.isString(body) ?
_zumoFeatures.GenericApiCall :
_zumoFeatures.JsonApiCall);
}
if (!_.isNull(parameters)) {
features.push(_zumoFeatures.AdditionalQueryParameters);
}
// Make the request
this._request(
method,
urlFragment,
body,
null,
headers,
features,
function (error, response) {
if (!_.isNull(error)) {
callback(error, null);
} else {
var contentType;
if (typeof response.getResponseHeader !== 'undefined') { // (when not using IframeTransport, IE9)
contentType = response.getResponseHeader('Content-Type');
}
// If there was no header / can't get one, try json
if (!contentType) {
try {
response.result = _.fromJson(response.responseText);
} catch(e) {
// Do nothing, since we don't know the content-type, failing may be ok
}
} else if (contentType.toLowerCase().indexOf('json') !== -1) {
response.result = _.fromJson(response.responseText);
}
callback(null, response);
}
});
});
function getApplicationInstallationId() {
///
/// Gets or creates the static application installation ID.
///
///
/// The application installation ID.
///
// Get or create a new installation ID that can be passed along on each
// request to provide telemetry data
var applicationInstallationId = null;
// Check if the config settings exist
var path = "MobileServices.Installation.config";
var contents = Platform.readSetting(path);
if (!_.isNull(contents)) {
// Parse the contents of the file as JSON and pull out the
// application's installation ID.
try {
var config = _.fromJson(contents);
applicationInstallationId = config.applicationInstallationId;
} catch (ex) {
// Ignore any failures (like invalid JSON, etc.) which will allow
// us to fall through to and regenerate a valid config below
}
}
// If no installation ID was found, generate a new one and save the config
// settings. This is pulled out as a separate function because we'll do it
// even if we successfully read an existing config but there's no
// installation ID.
if (_.isNullOrEmpty(applicationInstallationId)) {
applicationInstallationId = _.createUniqueInstallationId();
// TODO: How many other settings should we write out as well?
var configText = _.toJson({ applicationInstallationId: applicationInstallationId });
Platform.writeSetting(path, configText);
}
return applicationInstallationId;
}
///
/// Get or set the static _applicationInstallationId by checking the settings
/// and create the value if necessary.
///
MobileServiceClient._applicationInstallationId = getApplicationInstallationId();
///
/// Get or set the static _userAgent by calling into the Platform.
///
MobileServiceClient._userAgent = Platform.getUserAgent();
///
/// The features that are sent to the server for telemetry.
///
MobileServiceClient._zumoFeatures = _zumoFeatures;
================================================
FILE: sdk/Javascript/src/MobileServiceLogin.js
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
///
///
///
var _ = require('Extensions');
var Validate = require('Validate');
var Platform = require('Platform');
var loginUrl = "login";
var loginDone = "done";
function MobileServiceLogin(client, ignoreFilters) {
///
/// Initializes a new instance of the MobileServiceLogin class.
///
///
/// Reference to the MobileServiceClient associated with this login.
///
///
/// Optional parameter to indicate if the client filters should be ignored
/// and requests should be sent directly. Is true by default. This should
/// only be set to false for testing purposes when filters are needed to intercept
/// and validate requests and responses.
///
// Account for absent optional arguments
if (_.isNull(ignoreFilters)) {
ignoreFilters = true;
}
// Validate arguments
Validate.notNull(client);
Validate.isObject(client, 'client');
// Create read/write fields
this._loginState = { inProcess: false, cancelCallback: null };
this.ignoreFilters = ignoreFilters;
// Create get accessors for read-only fields
this.getMobileServiceClient = function () {
///
/// Gets the MobileServiceClient associated with this table.
///
///
/// The MobileServiceClient associated with this table.
///
return client;
};
this.getLoginInProcess = function () {
///
/// Indicates if a login is currently in process or not.
///
///
/// True if a login is in process and false otherwise.
///
return this._loginState.inProcess;
};
}
// Export the MobileServiceLogin class
exports.MobileServiceLogin = MobileServiceLogin;
// Define the MobileServiceLogin in a namespace (note: this has global effects
// unless the platform we're using chooses to ignore it because exports are
// good enough).
Platform.addToMobileServicesClientNamespace({ MobileServiceLogin: MobileServiceLogin });
MobileServiceLogin.prototype.loginWithOptions = function (provider, options, callback) {
///
/// Log a user into a Mobile Services application given a provider name with
/// given options.
///
///
/// Name of the authentication provider to use; one of 'facebook', 'twitter', 'google',
/// 'windowsazureactivedirectory' (can also use 'aad')
/// or 'microsoftaccount'.
///
///
/// Contains additional parameter information, valid values are:
/// token: provider specific object with existing OAuth token to log in with
/// useSingleSignOn: Only applies to Windows 8 clients. Will be ignored on other platforms.
/// Indicates if single sign-on should be used. Single sign-on requires that the
/// application's Package SID be registered with the Microsoft Azure Mobile Service,
/// but it provides a better experience as HTTP cookies are supported so that users
/// do not have to login in everytime the application is launched.
/// parameters: Any additional provider specific query string parameters.
///
///
/// Optional callback accepting (error, user) parameters.
///
Validate.isString(provider, 'provider');
Validate.notNull(provider, 'provider');
if (_.isNull(callback)) {
if (!_.isNull(options) && typeof options === 'function') {
callback = options;
options = null;
} else {
Validate.notNull(null, 'callback');
}
}
// loginWithOptions('a.b.c')
if (!options && this._isAuthToken(provider)) {
this.loginWithMobileServiceToken(provider, callback);
} else {
// loginWithOptions('facebook', {});
// loginWithOptions('facebook');
options = options || {};
this.loginWithProvider(provider, options.token, options.useSingleSignOn, options.parameters, callback);
}
};
MobileServiceLogin.prototype.login = function (provider, token, useSingleSignOn, callback) {
///
/// Log a user into a Mobile Services application given a provider name and optional token object
/// Microsoft Account authentication token.
///
///
/// Optional name of the authentication provider to use; one of 'facebook', 'twitter', 'google',
/// 'windowsazureactivedirectory' (can also use 'aad'), or 'microsoftaccount'.
///
///
/// Optional provider specific object with existing OAuth token to log in with or
/// a JWT Mobile Services authentication token if the provider is null.
///
///
/// Only applies to Windows 8 clients. Will be ignored on other platforms.
/// Indicates if single sign-on should be used. Single sign-on requires that the
/// application's Package SID be registered with the Microsoft Azure Mobile Service,
/// but it provides a better experience as HTTP cookies are supported so that users
/// do not have to login in everytime the application is launched.
///
///
/// Optional callback accepting (error, user) parameters.
///
// Account for absent optional arguments
if (_.isNull(callback)) {
if (!_.isNull(useSingleSignOn) && (typeof useSingleSignOn === 'function')) {
callback = useSingleSignOn;
useSingleSignOn = null;
}
else if (!_.isNull(token) && (typeof token === 'function')) {
callback = token;
useSingleSignOn = null;
token = null;
}
}
if (_.isNull(useSingleSignOn)) {
if (_.isBool(token)) {
useSingleSignOn = token;
token = null;
}
else {
useSingleSignOn = false;
}
}
// Determine if the provider is actually a Mobile Services authentication token
if (_.isNull(token) && this._isAuthToken(provider)) {
token = provider;
provider = null;
}
// Validate parameters; there must be either a provider, a token or both
if (_.isNull(provider)) {
Validate.notNull(token);
Validate.isString(token);
}
if (_.isNull(token)) {
Validate.notNull(provider);
Validate.isString(provider);
provider = provider.toLowerCase();
}
if (!_.isNull(provider)) {
if (provider.toLowerCase() === 'windowsazureactivedirectory') {
// The mobile service REST API uses '/login/aad' for Microsoft Azure Active Directory
provider = 'aad';
}
this.loginWithProvider(provider, token, useSingleSignOn, {}, callback);
}
else {
this.loginWithMobileServiceToken(token, callback);
}
};
MobileServiceLogin.prototype._isAuthToken = function (value) {
return value && _.isString(value) && value.split('.').length === 3;
};
MobileServiceLogin.prototype.loginWithMobileServiceToken = function(authenticationToken, callback) {
///
/// Log a user into a Mobile Services application given an Mobile Service authentication token.
///
///
/// OAuth access token that authenticates the user.
///
///
/// Optional callback accepting (error, user) parameters.
///
var self = this;
var client = self.getMobileServiceClient();
Validate.isString(authenticationToken, 'authenticationToken');
Validate.notNullOrEmpty(authenticationToken, 'authenticationToken');
client._request(
'POST',
loginUrl,
{ authenticationToken: authenticationToken },
self.ignoreFilters,
function(error, response) {
onLoginResponse(error, response, client, callback);
});
};
MobileServiceLogin.prototype.loginWithProvider = function(provider, token, useSingleSignOn, parameters, callback) {
///
/// Log a user into a Mobile Services application given a provider name and optional token object.
///
///
/// Name of the authentication provider to use; one of 'facebook', 'twitter', 'google',
/// 'windowsazureactivedirectory' (can also use 'aad'), or 'microsoftaccount'.
///
///
/// Optional, provider specific object with existing OAuth token to log in with.
///
///
/// Optional, indicates if single sign-on should be used. Single sign-on requires that the
/// application's Package SID be registered with the Microsoft Azure Mobile Service, but it
/// provides a better experience as HTTP cookies are supported so that users do not have to
/// login in everytime the application is launched. Is false be default.
///
///
/// Any additional provider specific query string parameters.
///
///
/// The callback to execute when the login completes: callback(error, user).
///
// Validate arguments
Validate.isString(provider, 'provider');
if (!_.isNull(token)) {
Validate.isObject(token, 'token');
}
// Throw if a login is already in process and is not cancellable
if (this._loginState.inProcess) {
var didCancel = this._loginState.cancelCallback && this._loginState.cancelCallback();
if (!didCancel) {
throw Platform.getResourceString("MobileServiceLogin_LoginErrorResponse");
}
}
provider = provider.toLowerCase();
// Either login with the token or the platform specific login control.
if (!_.isNull(token)) {
loginWithProviderAndToken(this, provider, token, parameters, callback);
}
else {
loginWithLoginControl(this, provider, useSingleSignOn, parameters, callback);
}
};
function onLoginComplete(error, token, client, callback) {
///
/// Handles the completion of the login and calls the user's callback with
/// either a user or an error.
///
///
/// Optional error that may have occurred during login. Will be null if the
/// login succeeded and their is a token.
///
///
/// Optional token that represents the logged-in user. Will be null if the
/// login failed and their is an error.
///
///
/// The Mobile Service client associated with the login.
///
///
/// The callback to execute when the login completes: callback(error, user).
///
var user = null;
if (_.isNull(error)) {
// Validate the token
if (_.isNull(token) ||
!_.isObject(token) ||
!_.isObject(token.user) ||
!_.isString(token.authenticationToken)) {
error = Platform.getResourceString("MobileServiceLogin_InvalidResponseFormat");
}
else {
// Set the current user on the client and return it in the callback
client.currentUser = token.user;
client.currentUser.mobileServiceAuthenticationToken = token.authenticationToken;
user = client.currentUser;
}
}
if (!_.isNull(callback)) {
callback(error, user);
}
}
function onLoginResponse(error, response, client, callback) {
///
/// Handles the completion of the login HTTP call and calls the user's callback with
/// either a user or an error.
///
///
/// Optional error that may have occurred during login. Will be null if the
/// login succeeded and their is a token.
///
///
/// Optional HTTP login response from the Mobile Service. Will be null if the
/// login failed and their is an error.
///
///
/// The Mobile Service client associated with the login.
///
///
/// The callback to execute when the login completes: callback(error, user).
///
var mobileServiceToken = null;
if (_.isNull(error)) {
try {
mobileServiceToken = _.fromJson(response.responseText);
}
catch (e) {
error = e;
}
}
onLoginComplete(error, mobileServiceToken, client, callback);
}
function loginWithProviderAndToken(login, provider, token, parameters, callback) {
///
/// Log a user into a Mobile Services application given a provider name and token object.
///
///
/// The login instance that holds the context used with the login process.
///
///
/// Name of the authentication provider to use; one of 'facebook', 'twitter', 'google', or
/// 'microsoftaccount'. The provider should already have been validated.
///
///
/// Provider specific object with existing OAuth token to log in with.
///
///
/// Any additional provider specific query string parameters.
///
///
/// The callback to execute when the login completes: callback(error, user).
///
var client = login.getMobileServiceClient();
// This design has always been problematic, because the operation can take arbitrarily
// long and there is no way for the UI to cancel it. We should probably remove this
// one-at-a-time restriction.
login._loginState = { inProcess: true, cancelCallback: null };
var url = loginUrl + '/' + provider;
if (!_.isNull(parameters)) {
var queryString = _.url.getQueryString(parameters);
url = _.url.combinePathAndQuery(url, queryString);
}
// Invoke the POST endpoint to exchange provider-specific token for a
// Microsoft Azure Mobile Services token
client._request(
'POST',
url,
token,
login.ignoreFilters,
function (error, response) {
login._loginState = { inProcess: false, cancelCallback: null };
onLoginResponse(error, response, client, callback);
});
}
function loginWithLoginControl(login, provider, useSingleSignOn, parameters, callback) {
///
/// Log a user into a Mobile Services application using a platform specific
/// login control that will present the user with the given provider's login web page.
///
///
/// The login instance that holds the context used with the login process.
///
///
/// Name of the authentication provider to use; one of 'facebook', 'twitter', 'google', or 'microsoftaccount'.
///
///
/// Optional, indicates if single sign-on should be used. Single sign-on requires that the
/// application's Package SID be registered with the Microsoft Azure Mobile Service, but it
/// provides a better experience as HTTP cookies are supported so that users do not have to
/// login in everytime the application is launched. Is false be default.
///
///
/// Any additional provider specific query string parameters.
///
///
/// The callback to execute when the login completes: callback(error, user).
///
var client = login.getMobileServiceClient();
var startUri = _.url.combinePathSegments(
client.applicationUrl,
loginUrl,
provider);
var endUri = null;
if (!_.isNull(parameters)) {
var queryString = _.url.getQueryString(parameters);
startUri = _.url.combinePathAndQuery(startUri, queryString);
}
// If not single sign-on, then we need to construct a non-null end uri.
if (!useSingleSignOn) {
endUri = _.url.combinePathSegments(
client.applicationUrl,
loginUrl,
loginDone);
}
login._loginState = { inProcess: true, cancelCallback: null }; // cancelCallback gets set below
// Call the platform to launch the login control, capturing any
// 'cancel' callback that it returns
var platformResult = Platform.login(
startUri,
endUri,
function (error, mobileServiceToken) {
login._loginState = { inProcess: false, cancelCallback: null };
onLoginComplete(error, mobileServiceToken, client, callback);
});
if (login._loginState.inProcess && platformResult && platformResult.cancelCallback) {
login._loginState.cancelCallback = platformResult.cancelCallback;
}
}
================================================
FILE: sdk/Javascript/src/MobileServiceTable.js
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
///
///
///
var _ = require('Extensions');
var Validate = require('Validate');
var Platform = require('Platform');
var Query = require('Query').Query;
// Name of the reserved Mobile Services ID member.
var idPropertyName = "id";
// The route separator used to denote the table in a uri like
// .../{app}/collections/{coll}.
var tableRouteSeperatorName = "tables";
var idNames = ["ID", "Id", "id", "iD"];
var nextLinkRegex = /^(.*?);\s*rel\s*=\s*(\w+)\s*$/;
var MobileServiceSystemProperties = {
None: 0,
CreatedAt: 1,
UpdatedAt: 2,
Version: 4,
All: 0xFFFF
};
var MobileServiceSystemColumns = {
CreatedAt: "__createdAt",
UpdatedAt: "__updatedAt",
Version: "__version"
};
Platform.addToMobileServicesClientNamespace({
MobileServiceTable:
{
SystemProperties: MobileServiceSystemProperties
}
});
function MobileServiceTable(tableName, client) {
///
/// Initializes a new instance of the MobileServiceTable class.
///
///
/// Name of the table.
///
///
/// The MobileServiceClient used to make requests.
///
this.getTableName = function () {
///
/// Gets the name of the table.
///
/// The name of the table.
return tableName;
};
this.getMobileServiceClient = function () {
///
/// Gets the MobileServiceClient associated with this table.
///
///
/// The MobileServiceClient associated with this table.
///
return client;
};
this.systemProperties = 0;
}
// Export the MobileServiceTable class
exports.MobileServiceTable = MobileServiceTable;
// We have an internal _read method using callbacks since it's used by both
// table.read(query) and query.read().
MobileServiceTable.prototype._read = function (query, parameters, callback) {
///
/// Query a table.
///
///
/// The query to execute. It can be null or undefined to get the entire
/// collection.
///
///
/// An object of user-defined parameters and values to include in the request URI query string.
///
///
/// The callback to invoke when the query is complete.
///
// Account for absent optional arguments
if (_.isNull(callback))
{
if (_.isNull(parameters) && (typeof query === 'function')) {
callback = query;
query = null;
parameters = null;
} else if (typeof parameters === 'function') {
callback = parameters;
parameters = null;
if (!_.isNull(query) && _.isObject(query)) {
// This 'query' argument could be either the query or the user-defined
// parameters object since both are optional. A query is either (a) a simple string
// or (b) an Object with an toOData member. A user-defined parameters object is just
// an Object. We need to detect which of these has been passed in here.
if (!_.isString(query) && _.isNull(query.toOData)) {
parameters = query;
query = null;
}
}
}
}
// Validate the arguments
if (query && _.isString(query)) {
Validate.notNullOrEmpty(query, 'query');
}
if (!_.isNull(parameters)) {
Validate.isValidParametersObject(parameters, 'parameters');
}
Validate.notNull(callback, 'callback');
// Get the query string
var tableName = this.getTableName();
var queryString = null;
var projection = null;
var features = [];
if (_.isString(query)) {
queryString = query;
if (!_.isNullOrEmpty(query)) {
features.push(WindowsAzure.MobileServiceClient._zumoFeatures.TableReadRaw);
}
} else if (_.isObject(query) && !_.isNull(query.toOData)) {
if (query.getComponents) {
features.push(WindowsAzure.MobileServiceClient._zumoFeatures.TableReadQuery);
var components = query.getComponents();
projection = components.projection;
if (components.table) {
// If the query has a table name, make sure it's compatible with
// the table executing the query
if (tableName !== components.table) {
var message = _.format(Platform.getResourceString("MobileServiceTable_ReadMismatchedQueryTables"), tableName, components.table);
callback(_.createError(message), null);
return;
}
// The oDataQuery will include the table name; we need to remove
// because the url fragment already includes the table name.
var oDataQuery = query.toOData();
queryString = oDataQuery.replace(new RegExp('^/' + components.table), '');
}
}
}
addQueryParametersFeaturesIfApplicable(features, parameters);
// Add any user-defined query string parameters
parameters = addSystemProperties(parameters, this.systemProperties, queryString);
if (!_.isNull(parameters)) {
var userDefinedQueryString = _.url.getQueryString(parameters);
if (!_.isNullOrEmpty(queryString)) {
queryString += '&' + userDefinedQueryString;
}
else {
queryString = userDefinedQueryString;
}
}
// Construct the URL
var urlFragment = queryString;
if (!_.url.isAbsoluteUrl(urlFragment)) {
urlFragment = _.url.combinePathSegments(tableRouteSeperatorName, tableName);
if (!_.isNull(queryString)) {
urlFragment = _.url.combinePathAndQuery(urlFragment, queryString);
}
}
// Make the request
this.getMobileServiceClient()._request(
'GET',
urlFragment,
null,
false,
null,
features,
function (error, response) {
var values = null;
if (_.isNull(error)) {
// Parse the response
values = _.fromJson(response.responseText);
// If the values include the total count, we'll attach that
// directly to the array
if (values &&
!Array.isArray(values) &&
typeof values.count !== 'undefined' &&
typeof values.results !== 'undefined') {
// Create a new total count property on the values array
values.results.totalCount = values.count;
values = values.results;
}
// If we have a projection function, apply it to each item
// in the collection
if (projection !== null) {
var i = 0;
for (i = 0; i < values.length; i++) {
values[i] = projection.call(values[i]);
}
}
// Grab link header when possible
if (Array.isArray(values) && response.getResponseHeader && _.isNull(values.nextLink)) {
try {
var link = response.getResponseHeader('Link');
if (!_.isNullOrEmpty(link)) {
var result = nextLinkRegex.exec(link);
// Only add nextLink when relation is next
if (result && result.length === 3 && result[2] == 'next') {
values.nextLink = result[1];
}
}
} catch (ex) {
// If cors doesn't allow us to access the Link header
// Just continue on without it
}
}
}
callback(error, values);
});
};
MobileServiceTable.prototype.read = Platform.async(MobileServiceTable.prototype._read);
MobileServiceTable.prototype.insert = Platform.async(
function (instance, parameters, callback) {
///
/// Insert a new object into a table.
///
///
/// The instance to insert into the table.
///
///
/// An object of user-defined parameters and values to include in the request URI query string.
///
///
/// The callback to invoke when the insert is complete.
///
// Account for absent optional arguments
if (_.isNull(callback) && (typeof parameters === 'function')) {
callback = parameters;
parameters = null;
}
// Validate the arguments
Validate.notNull(instance, 'instance');
if (!_.isNull(parameters)) {
Validate.isValidParametersObject(parameters);
}
Validate.notNull(callback, 'callback');
// Integer Ids can not have any Id set
for (var i in idNames) {
var id = instance[idNames[i]];
if (!_.isNullOrZero(id)) {
if (_.isString(id)) {
// String Id's are allowed iif using 'id'
if (idNames[i] !== idPropertyName) {
throw _.format(
Platform.getResourceString("MobileServiceTable_InsertIdAlreadySet"),
idPropertyName);
} else {
Validate.isValidId(id, idPropertyName);
}
} else {
throw _.format(
Platform.getResourceString("MobileServiceTable_InsertIdAlreadySet"),
idPropertyName);
}
}
}
var features = addQueryParametersFeaturesIfApplicable([], parameters);
// Construct the URL
var urlFragment = _.url.combinePathSegments(tableRouteSeperatorName, this.getTableName());
parameters = addSystemProperties(parameters, this.systemProperties);
if (!_.isNull(parameters)) {
var queryString = _.url.getQueryString(parameters);
urlFragment = _.url.combinePathAndQuery(urlFragment, queryString);
}
// Make the request
this.getMobileServiceClient()._request(
'POST',
urlFragment,
instance,
false,
null,
features,
function (error, response) {
if (!_.isNull(error)) {
callback(error, null);
} else {
var result = getItemFromResponse(response);
result = Platform.allowPlatformToMutateOriginal(instance, result);
callback(null, result);
}
});
});
MobileServiceTable.prototype.update = Platform.async(
function (instance, parameters, callback) {
///
/// Update an object in a given table.
///
///
/// The instance to update in the table.
///
///
/// An object of user-defined parameters and values to include in the request URI query string.
///
///
/// The callback to invoke when the update is complete.
///
var version,
headers = {},
features = [],
serverInstance;
// Account for absent optional arguments
if (_.isNull(callback) && (typeof parameters === 'function')) {
callback = parameters;
parameters = null;
}
// Validate the arguments
Validate.notNull(instance, 'instance');
Validate.isValidId(instance[idPropertyName], 'instance.' + idPropertyName);
if (!_.isNull(parameters)) {
Validate.isValidParametersObject(parameters, 'parameters');
}
Validate.notNull(callback, 'callback');
if (_.isString(instance[idPropertyName])) {
version = instance.__version;
serverInstance = removeSystemProperties(instance);
} else {
serverInstance = instance;
}
if (!_.isNullOrEmpty(version)) {
headers['If-Match'] = getEtagFromVersion(version);
features.push(WindowsAzure.MobileServiceClient._zumoFeatures.OptimisticConcurrency);
}
features = addQueryParametersFeaturesIfApplicable(features, parameters);
parameters = addSystemProperties(parameters, this.systemProperties);
// Construct the URL
var urlFragment = _.url.combinePathSegments(
tableRouteSeperatorName,
this.getTableName(),
encodeURIComponent(instance[idPropertyName].toString()));
if (!_.isNull(parameters)) {
var queryString = _.url.getQueryString(parameters);
urlFragment = _.url.combinePathAndQuery(urlFragment, queryString);
}
// Make the request
this.getMobileServiceClient()._request(
'PATCH',
urlFragment,
serverInstance,
false,
headers,
features,
function (error, response) {
if (!_.isNull(error)) {
setServerItemIfPreconditionFailed(error);
callback(error);
} else {
var result = getItemFromResponse(response);
result = Platform.allowPlatformToMutateOriginal(instance, result);
callback(null, result);
}
});
});
MobileServiceTable.prototype.refresh = Platform.async(
function (instance, parameters, callback) {
///
/// Refresh the current instance with the latest values from the
/// table.
///
///
/// The instance to refresh.
///
///
/// An object of user-defined parameters and values to include in the request URI query string.
///
///
/// The callback to invoke when the refresh is complete.
///
// Account for absent optional arguments
if (_.isNull(callback) && (typeof parameters === 'function')) {
callback = parameters;
parameters = null;
}
// Validate the arguments
Validate.notNull(instance, 'instance');
if (!_.isValidId(instance[idPropertyName], idPropertyName))
{
if (typeof instance[idPropertyName] === 'string' && instance[idPropertyName] !== '') {
throw _.format(Platform.getResourceString("Validate_InvalidId"), idPropertyName);
} else {
callback(null, instance);
}
return;
}
if (!_.isNull(parameters)) {
Validate.isValidParametersObject(parameters, 'parameters');
}
Validate.notNull(callback, 'callback');
// Construct the URL
var urlFragment = _.url.combinePathSegments(
tableRouteSeperatorName,
this.getTableName());
if (typeof instance[idPropertyName] === 'string') {
var id = encodeURIComponent(instance[idPropertyName]).replace(/\'/g, '%27%27');
urlFragment = _.url.combinePathAndQuery(urlFragment, "?$filter=id eq '" + id + "'");
} else {
urlFragment = _.url.combinePathAndQuery(urlFragment, "?$filter=id eq " + encodeURIComponent(instance[idPropertyName].toString()));
}
if (!_.isNull(parameters)) {
var queryString = _.url.getQueryString(parameters);
urlFragment = _.url.combinePathAndQuery(urlFragment, queryString);
}
var features = [WindowsAzure.MobileServiceClient._zumoFeatures.TableRefreshCall];
features = addQueryParametersFeaturesIfApplicable(features, parameters);
// Make the request
this.getMobileServiceClient()._request(
'GET',
urlFragment,
instance,
false,
null,
features,
function (error, response) {
if (!_.isNull(error)) {
callback(error, null);
} else {
var result = _.fromJson(response.responseText);
if (Array.isArray(result)) {
result = result[0]; //get first object from array
}
if (!result) {
var message =_.format(
Platform.getResourceString("MobileServiceTable_NotSingleObject"),
idPropertyName);
callback(_.createError(message), null);
}
result = Platform.allowPlatformToMutateOriginal(instance, result);
callback(null, result);
}
});
});
MobileServiceTable.prototype.lookup = Platform.async(
function (id, parameters, callback) {
///
/// Gets an instance from a given table.
///
///
/// The id of the instance to get from the table.
///
///
/// An object of user-defined parameters and values to include in the request URI query string.
///
///
/// The callback to invoke when the lookup is complete.
///
// Account for absent optional arguments
if (_.isNull(callback) && (typeof parameters === 'function')) {
callback = parameters;
parameters = null;
}
// Validate the arguments
Validate.isValidId(id, idPropertyName);
if (!_.isNull(parameters)) {
Validate.isValidParametersObject(parameters);
}
Validate.notNull(callback, 'callback');
// Construct the URL
var urlFragment = _.url.combinePathSegments(
tableRouteSeperatorName,
this.getTableName(),
encodeURIComponent(id.toString()));
var features = addQueryParametersFeaturesIfApplicable([], parameters);
parameters = addSystemProperties(parameters, this.systemProperties);
if (!_.isNull(parameters)) {
var queryString = _.url.getQueryString(parameters);
urlFragment = _.url.combinePathAndQuery(urlFragment, queryString);
}
// Make the request
this.getMobileServiceClient()._request(
'GET',
urlFragment,
null,
false,
null,
features,
function (error, response) {
if (!_.isNull(error)) {
callback(error, null);
} else {
var result = getItemFromResponse(response);
callback(null, result);
}
});
});
MobileServiceTable.prototype.del = Platform.async(
function (instance, parameters, callback) {
///
/// Delete an object from a given table.
///
///
/// The instance to delete from the table.
///
///
/// An object of user-defined parameters and values to include in the request URI query string.
///
///
/// The callback to invoke when the delete is complete.
///
// Account for absent optional arguments
if (_.isNull(callback) && (typeof parameters === 'function')) {
callback = parameters;
parameters = null;
}
// Validate the arguments
Validate.notNull(instance, 'instance');
Validate.isValidId(instance[idPropertyName], 'instance.' + idPropertyName);
Validate.notNull(callback, 'callback');
var headers = {};
var features = [];
if (_.isString(instance[idPropertyName])) {
if (!_.isNullOrEmpty(instance.__version)) {
headers['If-Match'] = getEtagFromVersion(instance.__version);
features.push(WindowsAzure.MobileServiceClient._zumoFeatures.OptimisticConcurrency);
}
}
features = addQueryParametersFeaturesIfApplicable(features, parameters);
parameters = addSystemProperties(parameters, this.systemProperties);
if (!_.isNull(parameters)) {
Validate.isValidParametersObject(parameters);
}
// Contruct the URL
var urlFragment = _.url.combinePathSegments(
tableRouteSeperatorName,
this.getTableName(),
encodeURIComponent(instance[idPropertyName].toString()));
if (!_.isNull(parameters)) {
var queryString = _.url.getQueryString(parameters);
urlFragment = _.url.combinePathAndQuery(urlFragment, queryString);
}
// Make the request
this.getMobileServiceClient()._request(
'DELETE',
urlFragment,
null,
false,
headers,
features,
function (error, response) {
if (!_.isNull(error)) {
setServerItemIfPreconditionFailed(error);
}
callback(error);
});
});
// Copy select Query operators to MobileServiceTable so queries can be created
// compactly. We'll just add them to the MobileServiceTable prototype and then
// forward on directly to a new Query instance.
var queryOperators =
['where', 'select', 'orderBy', 'orderByDescending', 'skip', 'take', 'includeTotalCount'];
var copyOperator = function (operator) {
MobileServiceTable.prototype[operator] = function () {
///
/// Creates a new query.
///
// Create a query associated with this table
var table = this;
var query = new Query(table.getTableName());
// Add a .read() method on the query which will execute the query.
// This method is defined here per query instance because it's
// implicitly tied to the table.
query.read = Platform.async(
function (parameters, callback) {
///
/// Execute the query.
///
table._read(query, parameters, callback);
});
// Invoke the query operator on the newly created query
return query[operator].apply(query, arguments);
};
};
var i = 0;
for (; i < queryOperators.length; i++) {
// Avoid unintended closure capture
copyOperator(queryOperators[i]);
}
// Table system properties
function removeSystemProperties(instance) {
var copy = {};
for(var property in instance) {
if (property.substr(0, 2) !== '__') {
copy[property] = instance[property];
}
}
return copy;
}
function addSystemProperties(parameters, properties, querystring) {
if (properties === MobileServiceSystemProperties.None || (typeof querystring === 'string' && querystring.toLowerCase().indexOf('__systemproperties') >= 0)) {
return parameters;
}
// Initialize an object if none passed in
parameters = parameters || {};
// Don't override system properties if already set
if(!_.isNull(parameters.__systemProperties)) {
return parameters;
}
if (properties === MobileServiceSystemProperties.All) {
parameters.__systemProperties = '*';
} else {
var options = [];
if (MobileServiceSystemProperties.CreatedAt & properties) {
options.push(MobileServiceSystemColumns.CreatedAt);
}
if (MobileServiceSystemProperties.UpdatedAt & properties) {
options.push(MobileServiceSystemColumns.UpdatedAt);
}
if (MobileServiceSystemProperties.Version & properties) {
options.push(MobileServiceSystemColumns.Version);
}
parameters.__systemProperties = options.join(',');
}
return parameters;
}
// Add double quotes and unescape any internal quotes
function getItemFromResponse(response) {
var result = _.fromJson(response.responseText);
if (response.getResponseHeader) {
var eTag = response.getResponseHeader('ETag');
if (!_.isNullOrEmpty(eTag)) {
result.__version = getVersionFromEtag(eTag);
}
}
return result;
}
// Converts an error to precondition failed error
function setServerItemIfPreconditionFailed(error) {
if (error.request && error.request.status === 412) {
error.serverInstance = _.fromJson(error.request.responseText);
}
}
// Add wrapping double quotes and escape all double quotes
function getEtagFromVersion(version) {
var result = version.replace(/\"/g, '\\\"');
return "\"" + result + "\"";
}
// Remove surrounding double quotes and unescape internal quotes
function getVersionFromEtag(etag) {
var len = etag.length,
result = etag;
if (len > 1 && etag[0] === '"' && etag[len - 1] === '"') {
result = etag.substr(1, len - 2);
}
return result.replace(/\\\"/g, '"');
}
// Updates and returns the headers parameters with features used in the call
function addQueryParametersFeaturesIfApplicable(features, userQueryParameters) {
var hasQueryParameters = false;
if (userQueryParameters) {
if (Array.isArray(userQueryParameters)) {
hasQueryParameters = userQueryParameters.length > 0;
} else if (_.isObject(userQueryParameters)) {
for (var k in userQueryParameters) {
hasQueryParameters = true;
break;
}
}
}
if (hasQueryParameters) {
features.push(WindowsAzure.MobileServiceClient._zumoFeatures.AdditionalQueryParameters);
}
return features;
}
================================================
FILE: sdk/Javascript/src/MobileServices.intellisense.js
================================================
// ----------------------------------------------------------------------------
//! Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
// Declare JSHint globals
/*global WindowsAzure:false, intellisense:false */
intellisense.annotate(WindowsAzure.MobileServiceClient.prototype, {
withFilter: function () {
///
///
/// Create a new MobileServiceClient with a filter inserted into the http
/// pipeline to process all of its HTTP requests and responses.
///
///
/// The filter to use on the service. The signature of a serviceFilter is
/// function(request, next, callback) where next := function(request, callback)
/// and callback := function(error, response).
///
///
/// A new MobileServiceClient whose HTTP requests and responses will be
/// filtered as desired.
///
///
},
login: function () {
///
///
/// Logs a user into a mobile service by using the specified identity provider.
///
///
/// The name of the identity provider, which instructs Mobile Services which provider to use for authentication.
/// The following values are supported: 'facebook', 'twitter', 'google', 'windowsazureactivedirectory' (can also use 'aad')
/// or 'microsoftaccount'. If no provider is specified, the 'token' parameter
/// is considered a Microsoft Account authentication token. If a provider is specified,
/// the 'token' parameter is considered a provider-specific authentication token.
///
///
/// Optional JSON representation of an authentication token, which can be supplied when the client has already
/// obtained a token from the identity provider.
///
///
/// Only applies to Windows 8 clients. Will be ignored on other platforms.
/// Indicates if single sign-on should be used. Single sign-on requires that the
/// application's Package SID be registered with the Microsoft Azure Mobile Service,
/// but it provides a better experience as HTTP cookies are supported so that users
/// do not have to login in everytime the application is launched.
///
///
/// A winJS.Promise object
///
///
},
logout: function () {
///
///
/// Logs a user out of a Mobile Services application.
///
///
}
});
intellisense.annotate(WindowsAzure, {
MobileServiceClient: function () {
///
///
/// Creates a new instance of the MobileServiceClient.
///
///
/// The URL of the mobile service..
///
///
/// The application key of the mobile service..
///
///
},
MobileServiceTable: function () {
///
///
/// Represents a table in a mobile service to support insert, update, delete, and query operations.
///
///
}
});
WindowsAzure.MobileServiceClient = (function () {
var _client = WindowsAzure.MobileServiceClient;
var wrapper = function () {
var instance = new _client();
intellisense.annotate(instance, {
/// The application key
applicationKey: String,
/// The current user
currentUser: undefined,
/// The application Url
applicationUrl: String,
getTable: function () {
///
///
/// Gets a reference to a table and its data operations.
///
/// The name of the table.
/// A reference to the table.
///
},
invokeApi: function () {
///
///
/// Invokes the specified custom api and returns a response object.
///
///
/// The custom api to invoke.
///
///
/// Contains additional parameter information, valid values are:
/// body: The body of the HTTP request.
/// method: The HTTP method to use in the request, with the default being POST,
/// parameters: Any additional query string parameters,
/// headers: HTTP request headers, specified as an object.
///
///
}
});
instance.getTable = (function () {
var _table = instance.getTable;
var wrapper2 = function () {
var instance2 = new _table();
intellisense.annotate(instance2, {
del: function () {
///
///
/// Deletes an object from a given table.
///
/// The instance to delete from the table.
/// A WinJS.Promise
///
},
getMobileServiceClient: function () {
///
///
/// The client associated with this table.
///
/// A MobileServiceClient
///
},
getTableName: function () {
///
///
/// The name of the table.
///
///
///
},
includeTotalCount: function () {
///
///
/// Indicate that the query should include the total count for all the records returned
/// ignoring any take paging limit clause specified.
///
/// A query that can be further composed.
///
},
insert: function () {
///
///
/// Inserts data from the supplied JSON object into the table.
///
///
/// The instance to insert into the table. It will be updated upon completion.
///
/// A WinJS.Promise
///
},
orderBy: function () {
///
///
/// Sorts a query against the table by the selected columns, in ascending order.
///
///
/// An array of the names of the columns to use for ordering
///
/// A query that can be further composed.
///
},
orderByDescending: function () {
///
///
/// Sorts a query against the table by the selected columns, in descending order.
///
///
/// An array of the names of the columns to use for ordering
///
/// A query that can be further composed.
///
},
read: function () {
///
///
/// Executes a query against the table.
///
///
/// The query to execute. When null or undefined, all rows are returned.
///
///
/// An object of user-defined parameters and values to include in the request URI query string.
///
/// A WinJS.Promise
///
},
lookup: function () {
///
///
/// Gets an instance from a given table.
///
///
/// The id of the instance to get from the table.
///
///
/// An object of user-defined parameters and values to include in the request URI query string.
///
/// A WinJS.Promise
///
},
refresh: function () {
///
///
/// Refresh the current instance with the latest values from the table.
///
///
/// The instance to refresh.
///
///
/// An object of user-defined parameters and values to include in the request URI query string.
///
/// A WinJS.Promise
///
},
select: function () {
///
///
/// Applies the specific column projection to the query against the table.
///
///
/// Function that defines the projection.
///
/// A query that can be further composed.
///
},
skip: function () {
///
///
/// Skips the specified number of rows in the query.
///
///
/// The number of rows to skip when returning the result.
///
/// A query that can be further composed.
///
},
take: function () {
///
///
/// Returns the specified number of rows in the query.
///
///
/// The number of rows in the query to return.
///
/// A query that can be further composed.
///
},
update: function () {
///
///
/// Updates an object in a given table.
///
///
/// The instance to update in the table, as a JSON object.
///
/// A WinJS.Promise
///
},
where: function () {
///
///
/// Applies a row filtering predicate to the query against the table.
///
///
/// JSON object that defines the row filter.
///
/// A query that can be further composed.
///
}
});
return instance2;
};
intellisense.redirectDefinition(wrapper2, _table);
return wrapper2;
})();
return instance;
};
intellisense.redirectDefinition(wrapper, _client);
return wrapper;
})();
================================================
FILE: sdk/Javascript/src/MobileServices.intellisense.txt
================================================
// Declare JSHint globals
/*global WindowsAzure:false, intellisense:false */
intellisense.annotate(WindowsAzure.MobileServiceClient.prototype, {
withFilter: function () {
///
///
/// Create a new MobileServiceClient with a filter inserted into the http
/// pipeline to process all of its HTTP requests and responses.
///
///
/// The filter to use on the service. The signature of a serviceFilter is
/// function(request, next, callback) where next := function(request, callback)
/// and callback := function(error, response).
///
///
/// A new MobileServiceClient whose HTTP requests and responses will be
/// filtered as desired.
///
///
},
login: function () {
///
///
/// Logs a user into a mobile service by using the specified identity provider.
///
///
/// The name of the identity provider, which instructs Mobile Services which provider to use for authentication.
/// The following values are supported: 'facebook', 'twitter', 'google',
/// or 'microsoftaccount'. If no provider is specified, the 'token' parameter
/// is considered a Microsoft Account authentication token. If a provider is specified,
/// the 'token' parameter is considered a provider-specific authentication token.
///
///
/// Optional JSON representation of an authentication token, which can be supplied when the client has already
/// obtained a token from the identity provider.
///
///
/// Only applies to Windows 8 clients. Will be ignored on other platforms.
/// Indicates if single sign-on should be used. Single sign-on requires that the
/// application's Package SID be registered with the Microsoft Azure Mobile Service,
/// but it provides a better experience as HTTP cookies are supported so that users
/// do not have to login in everytime the application is launched.
///
///
/// A winJS.Promise object
///
///
},
logout: function () {
///
///
/// Logs a user out of a Mobile Services application.
///
///
}
});
intellisense.annotate(WindowsAzure, {
MobileServiceClient: function () {
///
///
/// Creates a new instance of the MobileServiceClient.
///
///
/// The URL of the mobile service..
///
///
/// The application key of the mobile service..
///
/// PAV
///
},
MobileServiceTable: function () {
///
///
/// Represents a table in a mobile service to support insert, update, delete, and query operations.
///
///
}
});
WindowsAzure.MobileServiceClient = (function () {
var _client = WindowsAzure.MobileServiceClient;
var wrapper = function () {
var instance = new _client();
intellisense.annotate(instance, {
/// The application key
applicationKey: String,
/// The current user
currentUser: undefined,
/// The application Url
applicationUrl: String,
getTable: function () {
///
///
/// Gets a reference to a table and its data operations.
///
/// The name of the table.
/// A reference to the table.
///
}
});
instance.getTable = (function () {
var _table = instance.getTable;
var wrapper2 = function () {
var instance2 = new _table();
intellisense.annotate(instance2, {
del: function () {
///
///
/// Deletes an object from a given table.
///
/// The instance to delete from the table.
/// A WinJS.Promise
///
},
getMobileServiceClient: function () {
///
///
/// The client associated with this table.
///
/// A MobileServiceClient
///
},
getTableName: function () {
///
///
/// The name of the table.
///
///
///
},
includeTotalCount: function () {
///
///
/// Indicate that the query should include the total count for all the records returned
/// ignoring any take paging limit clause specified.
///
/// A query that can be further composed.
///
},
insert: function () {
///
///
/// Inserts data from the supplied JSON object into the table.
///
///
/// The instance to insert into the table. It will be updated upon completion.
///
/// A WinJS.Promise
///
},
orderBy: function () {
///
///
/// Sorts a query against the table by the selected columns, in ascending order.
///
///
/// The name of the first column to use for ordering
///
///
/// The name of the second column to use for ordering
///
/// A query that can be further composed.
///
},
orderByDescending: function () {
///
///
/// Inserts data from the supplied JSON object into the table.
///
///
/// The name of the first column to use for ordering
///
///
/// The name of the second column to use for ordering
///
/// A query that can be further composed.
///
},
read: function () {
///
///
/// Executes a query against the table.
///
///
/// The query to execute. When null or undefined, all rows are returned.
///
///
/// An object of user-defined parameters and values to include in the request URI query string.
///
/// A WinJS.Promise
///
},
select: function () {
///
///
/// Applies the specific column projection to the query against the table.
///
///
/// Function that defines the projection.
///
/// A query that can be further composed.
///
},
skip: function () {
///
///
/// Skips the specified number of rows in the query.
///
///
/// The number of rows to skip when returning the result.
///
/// A query that can be further composed.
///
},
take: function () {
///
///
/// Returns the specified number of rows in the query.
///
///
/// The number of rows in the query to return.
///
/// A query that can be further composed.
///
},
update: function () {
///
///
/// Updates an object in a given table.
///
///
/// The instance to update in the table, as a JSON object.
///
/// A WinJS.Promise
///
},
where: function () {
///
///
/// Applies a row filtering predicate to the query against the table.
///
///
/// JSON object that defines the row filter.
///
/// A query that can be further composed.
///
}
});
return instance2;
};
intellisense.redirectDefinition(wrapper2, _table);
return wrapper2;
})();
return instance;
};
intellisense.redirectDefinition(wrapper, _client);
return wrapper;
})();
================================================
FILE: sdk/Javascript/src/MobileServices.priconfig.xml
================================================
================================================
FILE: sdk/Javascript/src/Platforms/Platform.Web.js
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
///
/*global $__fileVersion__:false, $__version__:false */
var _ = require('Extensions');
var Validate = require('Validate');
var Promises = require('Promises');
var Resources = require('Resources');
var inMemorySettingStore = {};
try {
var key = '___z';
localStorage.setItem(key, key);
localStorage.removeItem(key);
inMemorySettingStore = localStorage;
} catch (e) {
// localStorage is not available
}
var bestAvailableTransport = null;
var knownTransports = [ // In order of preference
require('DirectAjaxTransport'),
require('IframeTransport')
];
var knownLoginUis = [ // In order of preference
require('WebAuthBroker'),
require('CordovaPopup'),
require('BrowserPopup')
];
// Matches an ISO date and separates out the fractional part of the seconds
// because IE < 10 has quirks parsing fractional seconds
var isoDateRegex = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(?:\.(\d*))?Z$/;
// Feature-detect IE8's date serializer
var dateSerializerOmitsDecimals = !JSON.stringify(new Date(100)).match(/\.100Z"$/);
exports.async = function async(func) {
///
/// Wrap a function that takes a callback into platform specific async
/// operation (i.e., keep using callbacks or switch to promises).
///
///
/// An async function with a callback as its last parameter
///
///
/// Function that when invoked will return a promise.
///
return function () {
// Capture the context of the original call
var that = this;
var args = arguments;
// Create a new promise that will wrap the async call
return new Promises.Promise(function (complete, error) {
// Add a callback to the args which will call the appropriate
// promise handlers
var callback = function (err) {
if (_.isNull(err)) {
// Call complete with all the args except for err
complete.apply(null, Array.prototype.slice.call(arguments, 1));
} else {
error(err);
}
};
Array.prototype.push.call(args, callback);
try {
// Invoke the async method which will in turn invoke our callback
// which will in turn invoke the promise's handlers
func.apply(that, args);
} catch (ex) {
// Thread any immediate errors like parameter validation
// through the the callback
callback(_.createError(ex));
}
});
};
};
exports.addToMobileServicesClientNamespace = function (declarations) {
///
/// Define a collection of declarations in the Mobile Services Client namespace.
///
///
/// Object consisting of names and values to define in the namespace.
///
// First ensure our 'WindowsAzure' namespace exists
var namespaceObject = global.WindowsAzure = global.WindowsAzure || {};
// Now add each of the declarations to the namespace
for (var key in declarations) {
if (declarations.hasOwnProperty(key)) {
namespaceObject[key] = declarations[key];
}
}
};
exports.readSetting = function readSetting(name) {
///
/// Read a setting from a global configuration store.
///
///
/// Name of the setting to read.
///
///
/// The value of the setting or null if not set.
///
return inMemorySettingStore[name];
};
exports.writeSetting = function writeSetting(name, value) {
///
/// Write a setting to a global configuration store.
///
///
/// Name of the setting to write.
///
///
/// The value of the setting.
///
inMemorySettingStore[name] = value;
};
exports.webRequest = function (request, callback) {
///
/// Make a web request.
///
///
/// Object describing the request (in the WinJS.xhr format).
///
///
/// The callback to execute when the request completes.
///
return getBestTransport().performRequest(request, callback);
};
exports.getUserAgent = function () {
// Browsers don't allow you to set a custom user-agent in ajax requests. Trying to do so
// will cause an exception. So we don't.
return null;
};
exports.getOperatingSystemInfo = function () {
return {
name: "--",
version: "--",
architecture: "--"
};
};
exports.getSdkInfo = function () {
var isCordovaEnvironment = window && window.cordova && window.cordova.version;
return {
language: isCordovaEnvironment ? "Cordova" : "Web",
fileVersion: $__fileVersion__
};
};
exports.login = function (startUri, endUri, callback) {
// Force logins to go over HTTPS because the runtime is hardcoded to redirect
// the server flow back to HTTPS, and we need the origin to match.
var findProtocol = /^[a-z]+:/,
requiredProtocol = 'https:';
startUri = startUri.replace(findProtocol, requiredProtocol);
endUri = endUri.replace(findProtocol, requiredProtocol);
return getBestProvider(knownLoginUis).login(startUri, endUri, callback);
};
exports.toJson = function (value) {
///
/// Convert an object into JSON format.
///
/// The value to convert.
/// The value as JSON.
// We're wrapping this so we can hook the process and perform custom JSON
// conversions. Note that we don't have to add a special hook to correctly
// serialize dates in ISO8061 because JSON.stringify does that by defualt.
// TODO: Convert geolocations once they're supported
// TODO: Expose the ability for developers to convert custom types
return JSON.stringify(value, function (key, stringifiedValue) {
if (dateSerializerOmitsDecimals && this && _.isDate(this[key])) {
// IE8 doesn't include the decimal part in its serialization of dates
// For consistency, we extract the non-decimal part from the string
// representation, and then append the expected decimal part.
var msec = this[key].getMilliseconds(),
msecString = String(msec + 1000).substring(1);
return stringifiedValue.replace(isoDateRegex, function (all, datetime) {
return datetime + "." + msecString + "Z";
});
} else {
return stringifiedValue;
}
});
};
exports.tryParseIsoDateString = function (text) {
///
/// Try to parse an ISO date string.
///
/// The text to parse.
/// The parsed Date or null.
Validate.isString(text);
// Check against a lenient regex
var matchedDate = isoDateRegex.exec(text);
if (matchedDate) {
// IE9 only handles precisely 0 or 3 decimal places when parsing ISO dates,
// and IE8 doesn't parse them at all. Fortunately, all browsers can handle
// 'yyyy/mm/dd hh:MM:ss UTC' (without fractional seconds), so we can rewrite
// the date to that format, and the apply fractional seconds.
var dateWithoutFraction = matchedDate[1],
fraction = matchedDate[2] || "0",
milliseconds = Math.round(1000 * Number("0." + fraction)); // 6 -> 600, 65 -> 650, etc.
dateWithoutFraction = dateWithoutFraction
.replace(/\-/g, "/") // yyyy-mm-ddThh:mm:ss -> yyyy/mm/ddThh:mm:ss
.replace("T", " "); // yyyy/mm/ddThh:mm:ss -> yyyy/mm/dd hh:mm:ss
// Try and parse - it will return NaN if invalid
var ticks = Date.parse(dateWithoutFraction + " UTC");
if (!isNaN(ticks)) {
return new Date(ticks + milliseconds); // ticks are just milliseconds since 1970/01/01
}
}
// Doesn't look like a date
return null;
};
exports.getResourceString = function (resourceName) {
// For now, we'll just always use English
return Resources["en-US"][resourceName];
};
exports.allowPlatformToMutateOriginal = function (original, updated) {
// For the Web/HTML client, we don't modify the original object.
// This is the more typical arrangement for most JavaScript data access.
return updated;
};
function getBestTransport() {
// We cache this just because it gets called such a lot
if (!bestAvailableTransport) {
bestAvailableTransport = getBestProvider(knownTransports);
}
return bestAvailableTransport;
}
function getBestProvider(providers) {
///
/// Given an array of objects which each have a 'supportsCurrentRuntime' function,
/// returns the first instance where that function returns true.
///
for (var i = 0; i < providers.length; i++) {
if (providers[i].supportsCurrentRuntime()) {
return providers[i];
}
}
throw new Error("Unsupported browser - no suitable providers are available.");
}
================================================
FILE: sdk/Javascript/src/Platforms/Platform.WinJS.js
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
///
///
///
// Declare JSHint globals
/*global WinJS:false, Windows:false, $__fileVersion__:false, $__version__:false */
var _ = require('Extensions'),
Validate = require('Validate'),
WebAuthBroker = require('WebAuthBroker');
exports.async = function async(func) {
///
/// Wrap a function that takes a callback into platform specific async
/// operation (i.e., keep using callbacks or switch to promises).
///
///
/// An async function with a callback as its last parameter
///
///
/// Function that when invoked will return a WinJS.Promise.
///
return function () {
// Capture the context of the original call
var that = this;
var args = arguments;
// Create a new promise that will wrap the async call
return new WinJS.Promise(function (complete, error) {
// Add a callback to the args which will call the appropriate
// promise handlers
var callback = function (err) {
if (_.isNull(err)) {
// Call complete with all the args except for err
complete.apply(null, Array.prototype.slice.call(arguments, 1));
} else {
error(err);
}
};
Array.prototype.push.call(args, callback);
try {
// Invoke the async method which will in turn invoke our callback
// which will in turn invoke the promise's handlers
func.apply(that, args);
} catch (ex) {
// Thread any immediate errors like parameter validation
// through the the callback
callback(_.createError(ex));
}
});
};
};
exports.addToMobileServicesClientNamespace = function (declarations) {
///
/// Define a collection of declarations in the Mobile Services Client namespace.
///
///
/// Object consisting of names and values to define in the namespace.
///
try {
WinJS.Namespace.define('WindowsAzure', declarations);
} catch (ex) {
// This can fail due to a WinRT issue where another assembly defining a
// non-JavaScript type with a Microsoft namespace. The wrapper object
// created to represent the namespace doesn't allow expando
// properties... so it will never let any additional JavaScript
// namespaces be defined under it. We only see this with our test
// library at the moment, but it could also appear if customers are
// using other Microsoft libraries in WinJS.
}
};
exports.readSetting = function readSetting(name) {
///
/// Read a setting from a global configuration store.
///
///
/// Name of the setting to read.
///
///
/// The value of the setting or null if not set.
///
var localSettings = Windows.Storage.ApplicationData.current.localSettings;
return !_.isNull(localSettings) ?
localSettings.values[name] :
null;
};
exports.writeSetting = function writeSetting(name, value) {
///
/// Write a setting to a global configuration store.
///
///
/// Name of the setting to write.
///
///
/// The value of the setting.
///
var localSettings = Windows.Storage.ApplicationData.current.localSettings;
if (!_.isNull(localSettings)) {
localSettings.values[name] = value;
}
};
exports.webRequest = function (request, callback) {
///
/// Make a web request.
///
///
/// Object describing the request (in the WinJS.xhr format).
///
///
/// The callback to execute when the request completes.
///
WinJS.xhr(request).done(
function (response) { callback(null, response); },
function (error) { callback(null, error); });
};
exports.login = function (startUri, endUri, callback) {
///
/// Log a user into a Mobile Services application by launching a
/// browser-based control that will allow the user to enter their credentials
/// with a given provider.
///
///
/// The absolute URI to which the login control should first navigate to in order to
/// start the login process flow.
///
///
/// The absolute URI that indicates login is complete. Once the login control navigates
/// to this URI, it will execute the callback.
///
///
/// The callback to execute when the login completes: callback(error, endUri).
///
// Account for absent optional arguments
if (_.isNull(callback) && typeof endUri === 'function') {
callback = endUri;
endUri = null;
}
Validate.notNullOrEmpty(startUri, 'startUri');
Validate.isString(startUri, 'startUri');
WebAuthBroker.login(startUri, endUri, callback);
};
exports.getOperatingSystemInfo = function () {
var architecture = "Unknown";
// The Windows API provides the architecture as an enum, so we have to
// lookup the string value
var archValue = Windows.ApplicationModel.Package.current.id.architecture;
switch (archValue) {
case 0: architecture = "X86"; break;
case 5: architecture = "Arm"; break;
case 9: architecture = "X64"; break;
case 11: architecture = "Neutral"; break;
}
return {
name: "Windows 8",
version: "--",
architecture: architecture
};
};
exports.getSdkInfo = function () {
return {
language: "WinJS",
fileVersion: $__fileVersion__
};
};
exports.getUserAgent = function () {
// The User-Agent header can not be set in WinJS
return null;
};
exports.toJson = function (value) {
///
/// Convert an object into JSON format.
///
/// The value to convert.
/// The value as JSON.
// We're wrapping this so we can hook the process and perform custom JSON
// conversions. Note that we don't have to add a special hook to correctly
// serialize dates in ISO8061 because JSON.stringify does that by defualt.
// TODO: Convert geolocations once they're supported
// TODO: Expose the ability for developers to convert custom types
return JSON.stringify(value);
};
exports.tryParseIsoDateString = function (text) {
///
/// Try to parse an ISO date string.
///
/// The text to parse.
/// The parsed Date or null.
Validate.isString(text);
// Check against a lenient regex
if (/^(\d{4})-(\d{2})-(\d{2})T(\d{2})\:(\d{2})\:(\d{2})(\.(\d{1,3}))?Z$/.test(text)) {
// Try and parse - it will return NaN if invalid
var ticks = Date.parse(text);
if (!isNaN(ticks)) {
// Convert to a regular Date
return new Date(ticks);
}
}
// Return null if not found
return null;
};
exports.getResourceString = function (resourceName) {
var resourceManager = Windows.ApplicationModel.Resources.Core.ResourceManager.current;
var resource = resourceManager.mainResourceMap.getValue("MobileServices/Resources/" + resourceName);
return resource.valueAsString;
};
exports.allowPlatformToMutateOriginal = function (original, updated) {
///
/// Patch an object with the values returned by from the server. Given
/// that it's possible for the server to change values on an insert/update,
/// we want to make sure the client object reflects those changes.
///
/// The original value.
/// The updated value.
/// The patched original object.
if (!_.isNull(original) && !_.isNull(updated)) {
var key = null;
var binding = WinJS.Binding.as(original);
for (key in updated) {
if (key in original) {
binding[key] = updated[key];
} else {
binding.addProperty(key, updated[key]);
}
}
// TODO: Should we also delete any fields on the original object that
// aren't also on the updated object? Is that a scenario for scripts?
}
return original;
};
================================================
FILE: sdk/Javascript/src/Properties/AssemblyInfo.cs
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
using System;
using System.Diagnostics.CodeAnalysis;
using System.Resources;
// NOTE: We're not actually using this project to generate a .NET class library
// so these settings are more or less meaningless. We've just got this project
// as there's no option for a "JavaScript Class Library" for Win8 projects.
[assembly: SuppressMessage(
"Microsoft.Design",
"CA2210:AssembliesShouldHaveValidStrongNames",
Justification = "Not an actual class library.")]
[assembly: NeutralResourcesLanguageAttribute("en-US")]
================================================
FILE: sdk/Javascript/src/Push/LocalStorageManager.js
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
///
///
///
// Declare JSHint globals
/*global WinJS:false, Windows:false */
var _ = require('Extensions'),
Validate = require('Validate'),
Platform = require('Platform'),
Constants = {
Version: 'v1.1.0',
Keys: {
Version: 'Version',
PushHandle: 'ChannelUri',
Registrations: 'Registrations',
NativeRegistration: '$Default'
},
};
function LocalStorageManager(storageKey) {
this._registrations = {};
this._storageKey = 'MobileServices.Push.' + storageKey;
this._isRefreshNeeded = false;
Object.defineProperty(this, 'isRefreshNeeded', {
get: function () {
///
/// Gets a value indicating whether local storage data needs to be refreshed.
///
return this._isRefreshNeeded;
}
});
this._pushHandle = null;
Object.defineProperty(this, 'pushHandle', {
get: function () {
///
/// Gets the DeviceId of all registrations in the LocalStorageManager
///
return _.isNull(this._pushHandle) ? '' : this._pushHandle;
},
set: function (value) {
Validate.notNullOrEmpty(value, 'pushHandle');
if (this._pushHandle !== value) {
this._pushHandle = value;
this._flushToSettings();
}
}
});
// Initialize our state
this._initializeRegistrationInfoFromStorage();
}
exports.LocalStorageManager = LocalStorageManager;
LocalStorageManager.NativeRegistrationName = Constants.Keys.NativeRegistration;
LocalStorageManager.prototype.getRegistrationIds = function () {
///
/// Gets an array of all registration Ids
///
///
/// An array of registration Ids in form of ['1','2','3']
///
var result = [];
for (var name in this._registrations) {
if (this._registrations.hasOwnProperty(name)) {
result.push(this._registrations[name]);
}
}
return result;
};
LocalStorageManager.prototype.getRegistrationIdWithName = function (registrationName) {
///
/// Get the registration Id from local storage
///
///
/// The name of the registration mapping to search for
///
///
/// The registration Id if it exists or null if it does not.
///
Validate.notNullOrEmpty(registrationName, 'registrationName');
return this._registrations[registrationName];
};
LocalStorageManager.prototype.updateAllRegistrations = function (registrations, pushHandle) {
///
/// Replace all registrations and the pushHandle with those passed in.
///
///
/// An array of registrations to update.
///
///
/// The pushHandle to update.
///
Validate.notNull(pushHandle, 'pushHandle');
if (!registrations) {
registrations = [];
}
this._registrations = {};
for (var i = 0; i < registrations.length; i++) {
var name = registrations[i].templateName;
if (_.isNullOrEmpty(name)) {
name = Constants.Keys.NativeRegistration;
}
/// All registrations passed to this method will have registrationId as they
/// come directly from notification hub where registrationId is the key field.
this._registrations[name] = registrations[i].registrationId;
}
// Need to flush explictly as handle may not have changed
this._pushHandle = pushHandle;
this._flushToSettings();
this._isRefreshNeeded = false;
};
LocalStorageManager.prototype.updateRegistrationWithName = function (registrationName, registrationId, pushHandle) {
///
/// Update a registration mapping and the deviceId in local storage by registrationName
///
///
/// The name of the registration mapping to update.
///
///
/// The registrationId to update.
///
///
/// The device Id to update the ILocalStorageManager to.
///
Validate.notNullOrEmpty(registrationName, 'registrationName');
Validate.notNullOrEmpty(registrationId, 'registrationId');
Validate.notNullOrEmpty(pushHandle, 'pushHandle');
// TODO: We could check if the Id or Name has actually changed
this._registrations[registrationName] = registrationId;
this._pushHandle = pushHandle;
this._flushToSettings();
};
LocalStorageManager.prototype.deleteRegistrationWithName = function (registrationName) {
///
/// Delete a registration from local storage by name
///
///
/// The name of the registration mapping to delete.
///
Validate.notNullOrEmpty(registrationName, 'registrationName');
if (this._registrations.hasOwnProperty(registrationName)) {
delete this._registrations[registrationName];
this._flushToSettings();
}
};
LocalStorageManager.prototype.deleteAllRegistrations = function () {
///
/// Clear all registrations from local storage.
///
this._registrations = {};
this._flushToSettings();
};
// Private methods
LocalStorageManager.prototype._flushToSettings = function () {
///
/// Writes all registrations to storage
///
var forStorage = {};
forStorage[Constants.Keys.Version] = Constants.Version;
forStorage[Constants.Keys.PushHandle] = this._pushHandle;
forStorage[Constants.Keys.Registrations] = this._registrations;
Platform.writeSetting(this._storageKey, JSON.stringify(forStorage));
};
LocalStorageManager.prototype._initializeRegistrationInfoFromStorage = function () {
///
/// Populates registration information from storage
///
this._registrations = {};
try {
// Read push handle
var data = JSON.parse(Platform.readSetting(this._storageKey));
this._pushHandle = data[Constants.Keys.PushHandle];
if (!this._pushHandle) {
this._isRefreshNeeded = true;
return;
}
// Verify this.storage version
var version = data[Constants.Keys.Version] || '';
this._isRefreshNeeded = (Constants.Version !== version.toLowerCase());
if (this._isRefreshNeeded) {
return;
}
// read registrations
this._registrations = data[Constants.Keys.Registrations];
} catch (err) {
// It is possible that local storage is corrupted by users, bugs or other issues.
// If this occurs, force a full refresh.
this._isRefreshNeeded = true;
}
};
================================================
FILE: sdk/Javascript/src/Push/Push.Web.js
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
///
///
///
var _ = require('Extensions'),
Validate = require('Validate'),
Platform = require('Platform'),
RegistrationManager = require('RegistrationManager').RegistrationManager,
apns = function (push) {
this._push = push;
},
gcm = function (push) {
this._push = push;
};
function Push(mobileServicesClient) {
this._apns = null;
this._gcm = null;
this._registrationManager = null;
Object.defineProperties(this, {
'apns': {
get: function () {
if (!this._apns) {
var name = _.format('MS-PushContainer-apns-{0}', mobileServicesClient.applicationUrl);
this._registrationManager = new RegistrationManager(mobileServicesClient, 'apns', name);
this._apns = new apns(this);
}
return this._apns;
}
},
'gcm': {
get: function () {
if (!this._gcm) {
var name = _.format('MS-PushContainer-gcm-{0}', mobileServicesClient.applicationUrl);
this._registrationManager = new RegistrationManager(mobileServicesClient, 'gcm', name);
this._gcm = new gcm(this);
}
return this._gcm;
}
}
});
}
exports.Push = Push;
Push.prototype._register = function (platform, pushHandle, tags) {
///
/// Register for native notification
///
///
/// The deviceToken to register
///
///
/// Array containing the tags for this registeration
///
///
/// Promise that will complete when the nregister is completed
///
var registration = makeCoreRegistration(pushHandle, platform, tags);
return this._registrationManager.upsertRegistration(registration);
};
Push.prototype._registerTemplate = function (platform, deviceToken, name, bodyTemplate, expiryTemplate, tags) {
///
/// Register for template notification
///
/// The deviceToken to register
/// The name of the template
///
/// The json body to register
///
///
/// The json body to register
///
///
/// Array containing the tags for this registeration
///
///
/// Promise that will complete when the register is completed
///
Validate.notNullOrEmpty(name, 'name');
Validate.notNullOrEmpty(bodyTemplate, 'bodyTemplate');
var templateAsString = bodyTemplate,
registration = makeCoreRegistration(deviceToken, platform, tags);
if (!_.isString(templateAsString)) {
templateAsString = JSON.stringify(templateAsString);
}
registration.templateName = name;
registration.templateBody = templateAsString;
if (expiryTemplate) {
registration.expiry = expiryTemplate;
}
return this._registrationManager.upsertRegistration(registration);
};
Push.prototype._unregister = function (templateName) {
///
/// Unregister for template notification
///
///
/// The name of the template
///
///
/// Promise that will complete when the unregister is completed
///
Validate.notNullOrEmpty(templateName, 'templateName');
return this._registrationManager.deleteRegistrationWithName(templateName);
};
Push.prototype._unregisterAll = function (pushHandle) {
///
/// Unregister for all notifications
///
///
/// The push handle to unregister everything for
///
///
/// Promise that will complete when the unregister is completed
///
Validate.notNullOrEmpty(pushHandle, 'pushHandle');
return this._registrationManager.deleteAllRegistrations(pushHandle);
};
apns.prototype.registerNative = function (deviceToken, tags) {
///
/// Register for native notification
///
///
/// The deviceToken to register
///
///
/// Array containing the tags for this registeration
///
///
/// Promise that will complete when the register is completed
///
return this._push._register('apns', deviceToken, tags);
};
apns.prototype.registerTemplate = function (deviceToken, name, bodyTemplate, expiryTemplate, tags) {
///
/// Register for template notification
///
/// The deviceToken to register
/// The name of the template
///
/// String or json object defining the body of the template register
///
///
/// String defining the datatime or template expresession that evaluates to a date time
/// string to use for the expiry of the message
///
///
/// Array containing the tags for this registeration
///
///
/// Promise that will complete when the unregister is completed
///
if (_.isNull(tags) && !_.isNull(expiryTemplate) && Array.isArray(expiryTemplate)) {
tags = expiryTemplate;
expiryTemplate = null;
}
return this._push._registerTemplate('apns', deviceToken, name, bodyTemplate, expiryTemplate, tags);
};
apns.prototype.unregisterNative = function () {
///
/// Unregister for native notification
///
///
/// Promise that will complete when the unregister is completed
///
return this._push._unregister(RegistrationManager.NativeRegistrationName);
};
apns.prototype.unregisterTemplate = function (templateName) {
///
/// Unregister for template notification
///
///
/// The name of the template
///
///
/// Promise that will complete when the unregister is completed
///
return this._push._unregister(templateName);
};
apns.prototype.unregisterAll = function (deviceToken) {
///
/// DEBUG-ONLY: Unregisters all registrations for the given device token
///
///
/// The device token
///
///
/// Promise that will complete once all registrations are deleted
///
return this._push._unregisterAll(deviceToken);
};
gcm.prototype.registerNative = function (deviceId, tags) {
///
/// Register for native notification
///
///
/// The deviceToken to register
///
///
/// Array containing the tags for this registeration
///
///
/// Promise that will complete when the unregister is completed
///
return this._push._register('gcm', deviceId, tags);
};
gcm.prototype.registerTemplate = function (deviceId, name, bodyTemplate, tags) {
///
/// Register for template notification
///
///
/// The deviceId to register
///
///
/// The name of the template
///
///
/// String or json object defining the body to register
///
///
/// Array containing the tags for this registeration
///
///
/// Promise that will complete when the unregister is completed
///
return this._push._registerTemplate('gcm', deviceId, name, bodyTemplate, null, tags);
};
gcm.prototype.unregisterNative = function () {
///
/// Unregister for native notification
///
///
/// Promise that will complete when the register is completed
///
return this._push._unregister(RegistrationManager.NativeRegistrationName);
};
gcm.prototype.unregisterTemplate = function (templateName) {
///
/// Unregister for template notification
///
///
/// The name of the template
///
///
/// Promise that will complete when the register is completed
///
return this._push._unregister(templateName);
};
gcm.prototype.unregisterAll = function (deviceId) {
///
/// DEBUG-ONLY: Unregisters all registrations for the given device token
///
///
/// The device id
///
///
/// Promise that will complete once all registrations are deleted
///
return this._push._unregisterAll(deviceId);
};
function makeCoreRegistration(pushHandle, platform, tags) {
Validate.notNullOrEmpty(pushHandle, 'pushHandle');
Validate.isString(pushHandle, 'pushHandle');
if (platform == 'apns') {
pushHandle = pushHandle.toUpperCase();
}
var registration = {
platform: platform,
deviceId: pushHandle
};
if (tags) {
Validate.isArray(tags, 'tags');
registration.tags = tags;
}
return registration;
}
================================================
FILE: sdk/Javascript/src/Push/Push.WinJS.js
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
///
///
///
var _ = require('Extensions'),
Validate = require('Validate'),
Platform = require('Platform'),
RegistrationManager = require('RegistrationManager').RegistrationManager;
function Push(mobileServicesClient, tileId) {
tileId = tileId || '$Primary';
var packageName = Windows.ApplicationModel.Package.current.id.name,
name = _.format('{0}-PushContainer-{1}-{2}', packageName, mobileServicesClient.applicationUrl, tileId);
this._registrationManager = new RegistrationManager(mobileServicesClient, 'wns', name);
}
exports.Push = Push;
Push.prototype.registerNative = function (channelUri, tags) {
///
/// Register for native notification
///
///
/// The channelUri to register
///
///
/// Array containing the tags for this registeration
///
///
/// A promise that will complete when the registration is complete.
///
var registration = makeCoreRegistration(channelUri, tags);
return this._registrationManager.upsertRegistration(registration);
};
Push.prototype.registerTemplate = function (channelUri, templateBody, templateName, headers, tags) {
///
/// Register for template notification
///
/// The channelUri to register
/// The xml body to register
/// The name of the template
/// Object containing key/value pairs for the template to provide to WNS. X-WNS-Type is required. Example: { 'X-WNS-Type' : 'wns/toast' }
/// Array containing the tags for this registeration
///
/// A promise that will complete when the registration is complete.
///
var registration = makeCoreRegistration(channelUri, tags);
if (templateBody) {
Validate.isString(templateBody, 'templateBody');
registration.templateBody = templateBody;
Validate.isString(templateName, 'templateName');
Validate.notNullOrEmpty(templateName);
registration.templateName = templateName;
if (headers) {
Validate.isObject(headers);
registration.headers = headers;
}
}
return this._registrationManager.upsertRegistration(registration);
};
Push.prototype.unregisterNative = function () {
///
/// Unregister for native notification
///
/// Promise that will complete when the unregister is completed
return this.unregisterTemplate(RegistrationManager.NativeRegistrationName);
};
Push.prototype.unregisterTemplate = function (templateName) {
///
/// Unregister for template notification
///
///
/// The name of the template
///
/// Promise that will complete when the unregister is completed
Validate.notNullOrEmpty(templateName, 'templateName');
return this._registrationManager.deleteRegistrationWithName(templateName);
};
Push.prototype.unregisterAll = function (channelUri) {
///
/// DEBUG-ONLY: Unregister all notifications for a specfic channelUri
///
/// The channelUri to unregister
/// Promise that will complete when the unregistration of all registrations at the channelUri is completed
Validate.notNullOrEmpty(channelUri, 'channelUri');
return this._registrationManager.deleteAllRegistrations(channelUri);
};
Push.prototype.getSecondaryTile = function (tileId) {
// TODO: move below to function
var packageName = Windows.ApplicationModel.Package.current.id.name,
name = _.format('{0}-PushContainer-{1}-{2}', packageName, mobileServicesClient.applicationUrl, tileId),
localStorage = new LocalStorageManager(name);
return new Push(name);
};
function makeCoreRegistration(channelUri, tags) {
var registration = {};
registration.platform = 'wns';
Validate.isString(channelUri, 'channelUri');
Validate.notNullOrEmpty(channelUri, 'channelUri');
registration.deviceId = channelUri;
if (tags) {
Validate.isArray(tags, 'tags');
registration.tags = tags;
}
return registration;
}
================================================
FILE: sdk/Javascript/src/Push/PushHttpClient.js
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
///
///
///
var Platform = require('Platform'),
noCacheHeader = { 'If-Modified-Since': 'Mon, 27 Mar 1972 00:00:00 GMT' };
function PushHttpClient(mobileServicesClient) {
this.mobileServicesClient = mobileServicesClient;
}
exports.PushHttpClient = PushHttpClient;
PushHttpClient.prototype.listRegistrations = function (pushHandle, platform, callback) {
this.mobileServicesClient._request(
'GET',
'/push/registrations?platform=' + encodeURIComponent(platform) + '&deviceId=' + encodeURIComponent(pushHandle),
null,
null,
noCacheHeader,
function (error, request) {
if (error) {
callback(error);
} else {
callback(null, JSON.parse(request.responseText));
}
});
};
PushHttpClient.prototype.unregister = function (registrationId, callback) {
this.mobileServicesClient._request(
'DELETE',
'/push/registrations/' + encodeURIComponent(registrationId),
null,
null,
noCacheHeader,
function (error) {
if (error && error.request && error.request.status === 404) {
callback();
return;
}
callback(error);
});
};
PushHttpClient.prototype.createRegistrationId = function (callback) {
this.mobileServicesClient._request(
'POST',
'/push/registrationIds',
null,
null,
noCacheHeader,
function (error, request) {
if (error) {
callback(error);
return;
}
var locationHeader = request.getResponseHeader('Location');
callback(null, locationHeader.slice(locationHeader.lastIndexOf('/') + 1));
});
};
PushHttpClient.prototype.upsertRegistration = function (registration, callback) {
this.mobileServicesClient._request(
'PUT',
'/push/registrations/' + encodeURIComponent(registration.registrationId),
registration,
null,
noCacheHeader,
callback);
};
================================================
FILE: sdk/Javascript/src/Push/RegistrationManager.js
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
///
///
///
// Declare JSHint globals
/*global WinJS:false */
var _ = require('Extensions'),
Validate = require('Validate'),
Platform = require('Platform'),
LocalStorageManager = require('LocalStorageManager').LocalStorageManager,
PushHttpClient = require('PushHttpClient').PushHttpClient;
function RegistrationManager(mobileServicesClient, platform, storageKey) {
Validate.notNull(mobileServicesClient, 'mobileServicesClient');
this._platform = platform || 'wns';
this._pushHttpClient = new PushHttpClient(mobileServicesClient);
this._storageManager = new LocalStorageManager(storageKey || mobileServicesClient.applicationUrl);
}
exports.RegistrationManager = RegistrationManager;
RegistrationManager.NativeRegistrationName = LocalStorageManager.NativeRegistrationName;
RegistrationManager.prototype.upsertRegistration = Platform.async(
function (registration, finalCallback) {
Validate.notNull(registration, 'registration');
Validate.notNull(finalCallback, 'callback');
var self = this,
expiredRegistration = function (callback) {
createRegistration(function (error) {
if (error) {
callback(error);
return;
}
upsertRegistration(false, callback);
});
},
upsertRegistration = function (retry, callback) {
self._pushHttpClient.upsertRegistration(registration, function (error) {
if (retry && error && error.request && error.request.status === 410) {
expiredRegistration(callback);
return;
} else if (!error) {
self._storageManager.pushHandle = registration.deviceId;
}
callback(error);
});
},
createRegistration = function (callback) {
self._pushHttpClient.createRegistrationId(function (error, registrationId) {
if (error) {
callback(error);
return;
}
registration.registrationId = registrationId;
self._storageManager.updateRegistrationWithName(
registration.templateName || LocalStorageManager.NativeRegistrationName,
registration.registrationId,
registration.deviceId);
callback();
});
},
firstRegistration = function (callback) {
var name = registration.templateName || LocalStorageManager.NativeRegistrationName,
cachedRegistrationId = self._storageManager.getRegistrationIdWithName(name);
if (!_.isNullOrEmpty(cachedRegistrationId)) {
registration.registrationId = cachedRegistrationId;
upsertRegistration(true, callback);
} else {
createRegistration(function (error) {
if (error) {
callback(error);
return;
}
upsertRegistration(true, callback);
});
}
};
if (this._storageManager.isRefreshNeeded) {
// We want the existing handle to win (if present), and slowly update them to the new handle
// So use cached value over the passed in value
this._refreshRegistrations(this._storageManager.pushHandle || registration.deviceId, function (error) {
if (error) {
finalCallback(error);
return;
}
firstRegistration(finalCallback);
});
} else {
firstRegistration(finalCallback);
}
});
RegistrationManager.prototype.deleteRegistrationWithName = Platform.async(
function (registrationName, callback) {
var cachedRegistrationId = this._storageManager.getRegistrationIdWithName(registrationName),
self = this;
if (_.isNullOrEmpty(cachedRegistrationId)) {
callback();
return;
}
this._pushHttpClient.unregister(cachedRegistrationId, function (error) {
if (!error) {
self._storageManager.deleteRegistrationWithName(registrationName);
}
callback(error);
});
});
RegistrationManager.prototype.deleteAllRegistrations = Platform.async(
function (pushHandle, callback) {
var self = this,
currentHandle = this._storageManager.pushHandle,
deleteRegistrations = function (error, deleteCallback) {
if (error) {
deleteCallback(error);
return;
}
var registrationIds = self._storageManager.getRegistrationIds(),
remaining = registrationIds.length,
errors = [];
if (remaining === 0) {
self._storageManager.deleteAllRegistrations();
deleteCallback();
return;
}
registrationIds.map(function (registrationId) {
self._pushHttpClient.unregister(registrationId, function (error) {
remaining--;
if (error) {
errors.push(error);
}
if (remaining <= 0) {
if (errors.length === 0) {
self._storageManager.deleteAllRegistrations();
deleteCallback();
} else {
deleteCallback(_.createError('Failed to delete registrations for ' + pushHandle));
}
}
});
});
};
Validate.notNull(pushHandle, 'pushHandle');
// Try to refresh with the local storage copy first, then if different use the requested one
this._refreshRegistrations(currentHandle || pushHandle, function (error) {
if (_.isNullOrEmpty(currentHandle) || pushHandle === currentHandle) {
deleteRegistrations(error, callback);
} else {
// Delete the current handle's registrations
deleteRegistrations(error, function (error) {
// Now delete the current handle's registrations as well
// This requires the deleteAllRegistrations() call to clear the cached handle
self._refreshRegistrations(pushHandle, function (error) {
deleteRegistrations(error, callback);
});
});
}
});
});
RegistrationManager.prototype.listRegistrations = Platform.async(
function (pushHandle, callback) {
///
/// Retrives a list of all registrations from the server
///
Validate.notNullOrEmpty(pushHandle);
this._pushHttpClient.listRegistrations(pushHandle, this._platform, callback);
});
RegistrationManager.prototype._refreshRegistrations = function (pushHandle, callback) {
///
/// Reloads all registrations for the pushHandle passed in
///
var self = this;
Validate.notNull(pushHandle, 'pushHandle');
Validate.notNull(callback, 'callback');
this._pushHttpClient.listRegistrations(pushHandle, this._platform, function (error, registrations) {
if (!error) {
self._storageManager.updateAllRegistrations(registrations, pushHandle);
}
callback(error);
});
};
================================================
FILE: sdk/Javascript/src/Require.js
================================================
///
/// Map module names to either their cached exports or a function which
/// will define the module's exports when invoked.
///
var $__modules__ = { };
function require(name) {
///
/// Require a module's exports.
///
///
/// The name of the module. Note that we don't support full CommonJS
/// Module specification names here - we only allow the name of the
/// module's file without any extension.
///
///
/// The exports provided by the module.
///
if (name && name.length > 2 && name[0] == '.' && name[1] == '/') {
name = name.slice(2);
}
var existing = $__modules__[name];
if (typeof existing == 'function') {
var exports = { };
$__modules__[name] = exports;
existing(exports);
return exports;
} else if (typeof existing == 'object') {
return existing;
} else {
throw 'Unknown module ' + name;
}
}
================================================
FILE: sdk/Javascript/src/Strings/en-US/Resources.resjson
================================================
{
"Validate_NotNullError" : "{0} cannot be null.",
"Validate_NotNullOrEmptyError" : "{0} cannot be null or empty.",
"Validate_InvalidId" : "{0} is not valid.",
"Validate_TypeCheckError" : "{0} is expected to be a value of type {1}, not {2}.",
"Validate_LengthUnexpected" : "{0} is expected to have length {1}, not {2}.",
"Validate_InvalidUserParameter" : "{0} contains an invalid user-defined query string parameter: {1}. User-defined query string parameters must not begin with a '$'.",
"Extensions_DefaultErrorMessage" : "Unexpected failure.",
"Extensions_ConnectionFailureMessage" : "Unexpected connection failure.",
"MobileServiceTable_ReadMismatchedQueryTables" : "Cannot get the results of a query for table '{1}' via table '{0}'.",
"MobileServiceTable_InsertIdAlreadySet" : "Cannot insert if the {0} member is already set.",
"MobileServiceLogin_AuthenticationProviderNotSupported" : "Unsupported authentication provider name. Please specify one of {0}.",
"MobileServiceLogin_LoginErrorResponse" : "Cannot start a login operation because login is already in progress.",
"MobileServiceLogin_InvalidResponseFormat" : "Invalid format of the authentication response.",
"MobileServiceLogin_InvalidProvider" : "The first parameter must be the name of the autentication provider or a Microsoft Account authentication token.",
"MobileServiceTable_NotSingleObject" : "Could not get object from response {0}.",
"Push_ConflictWithReservedName" : "Template name conflicts with reserved name '{0}'.",
"Push_InvalidTemplateName" : "Template name can't contain ';' or ':'.",
"Push_NotSupportedXMLFormatAsBodyTemplateWin8" : "The bodyTemplate is not in accepted XML format. The first node of the bodyTemplate should be Badge\/Tile\/Toast, except for the wns\/raw template, which need to be a valid XML.",
"Push_BodyTemplateMustBeXml" : "Valid XML is required for any template without a raw header.",
"Push_TagNoCommas" : "Tags must not contain ','."
}
================================================
FILE: sdk/Javascript/src/Transports/DirectAjaxTransport.js
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
///
// This transport is for modern browsers - it uses XMLHttpRequest with Cross-Origin Resource Sharing (CORS)
exports.name = "DirectAjaxTransport";
exports.supportsCurrentRuntime = function () {
///
/// Determines whether or not this transport is usable in the current runtime.
///
// Feature-detect support for CORS (for IE, it's in version 10+)
return (typeof global.XMLHttpRequest !== "undefined") &&
('withCredentials' in new global.XMLHttpRequest());
};
exports.performRequest = function (request, callback) {
///
/// Make a web request.
///
///
/// Object describing the request (in the WinJS.xhr format).
///
///
/// The callback to execute when the request completes.
///
var headers = request.headers || {},
url = request.url.replace(/#.*$/, ""), // Strip hash part of URL for consistency across browsers
httpMethod = request.type ? request.type.toUpperCase() : "GET",
xhr = new global.XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
callback(null, xhr);
}
};
xhr.open(httpMethod, url);
for (var key in headers) {
if (request.headers.hasOwnProperty(key)) {
xhr.setRequestHeader(key, request.headers[key]);
}
}
xhr.send(request.data);
};
================================================
FILE: sdk/Javascript/src/Transports/IframeTransport.js
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
///
// This transport is for midlevel browsers (IE8-9) that don't support CORS but do support postMessage.
// It creates an invisible
/// The test groups.
public override void Filter(IList groups)
{
string tagExpression = this.Settings.TagExpression;
if (!string.IsNullOrEmpty(tagExpression))
{
this.Settings.TestRunStatusMessage += " - Tag Expression '" + tagExpression + "'";
foreach (TestGroup group in groups)
{
List activeMethods =
new TagManager(group).EvaluateExpression(tagExpression).ToList();
Remove(group.Methods, m => !activeMethods.Contains(m));
}
Remove(groups, g => g.Methods.Count == 0);
}
}
}
}
================================================
FILE: sdk/Javascript/test/framework/TestFilter.cs
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Microsoft.Azure.Zumo.Win8.Test
{
///
/// A filter that can be used to exclude a set of tests.
///
internal abstract class TestFilter
{
///
/// Initializes a new instance of the TestFilter class.
///
/// The test settings.
public TestFilter(TestSettings settings)
{
Debug.Assert(settings != null, "settings should not be null!");
this.Settings = settings;
}
///
/// Gets the TestSettings to be used by the filter.
///
public TestSettings Settings { get; private set; }
///
/// Filter the test groups.
///
/// The groups to test.
public virtual void Filter(IList groups)
{
}
///
/// Remove the elements matching a given predicate.
///
/// Type of the element.
/// The elements to remove.
/// The predicate to compare.
protected static void Remove(IList elements, Func predicate)
{
Debug.Assert(elements != null, "elements cannot be null!");
Debug.Assert(predicate != null, "predicate cannot be null!");
foreach (T element in elements.Where(predicate).ToList())
{
elements.Remove(element);
}
}
}
}
================================================
FILE: sdk/Javascript/test/framework/TestGroup.cs
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
namespace Microsoft.Azure.Zumo.Win8.Test
{
///
/// A group of tests for a related functional area.
///
public sealed class TestGroup
{
///
/// Initializes a new instance of the TestGroup class.
///
public TestGroup()
{
this.Name = string.Empty;
this.Methods = new List();
this.Tags = new List();
}
///
/// Gets or sets the name of the test group.
///
public string Name { get; set; }
///
/// Gets the list of tags associated with this test group.
///
public IList Tags { get; private set; }
///
/// Gets the list of methods available in the test group.
///
public IList Methods { get; private set; }
///
/// Exclude all of the methods in a test group.
///
/// The reason to exclude the group.
public void Exclude(string reason)
{
foreach (TestMethod method in this.Methods)
{
// Only exclude if it isn't already to prevent stomping on the
// exclude reason
if (!method.Excluded)
{
method.Exclude(reason);
}
}
}
}
}
================================================
FILE: sdk/Javascript/test/framework/TestHarness.cs
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Xml.Linq;
namespace Microsoft.Azure.Zumo.Win8.Test
{
///
/// Harness for a test framework that allows asynchronous unit testing
/// across any WinRT framework independent of language (JS, C#, C++) or
/// UI framework (WWA, XAML).
///
public sealed class TestHarness
{
///
/// Initializes a new instance of the TestHarness class.
///
public TestHarness()
{
this.Groups = new List();
this.Settings = new TestSettings();
}
///
/// Gets the list of test groups which contain TestMethods to execute.
///
public IList Groups { get; private set; }
///
/// Gets the test settings used for this run.
///
public TestSettings Settings { get; private set; }
///
/// Gets or sets the TestReporter used to update the test interface as
/// the test run progresses.
///
public ITestReporter Reporter { get; set; }
///
/// Gets the total number of test methods.
///
///
/// This is a simple helper to provide access to the total number of
/// test methods which the Reporter can display.
///
public int Count
{
get { return this.Groups.SelectMany(g => g.Methods).Count(); }
}
///
/// Gets the number of test failures.
///
public int Failures { get; set; }
///
/// Get the number of tests already executed.
///
public int Progress { get; private set; }
///
/// Log a message.
///
/// The message.
public void Log(string message)
{
this.Reporter.Log(message);
}
///
/// Filter out any test methods basd on the current settings.
///
private void FilterTests()
{
// Create the list of filters (at some point we could make this
// publicly accessible)
List filters = new List();
filters.Add(new FunctionalTestFilter(this.Settings));
filters.Add(new RuntimeTestFilter(this.Settings));
filters.Add(new TagTestFilter(this.Settings));
// Apply any test filters to the set of tests before we begin
// executing (test filters will change the Excluded property of
// individual test methods)
int originalCount = Count;
foreach (TestFilter filter in filters)
{
filter.Filter(this.Groups);
}
int filteredCount = Count;
if (filteredCount != originalCount)
{
this.Settings.TestRunStatusMessage += " - Only running " + filteredCount + "/" + originalCount + " tests";
}
}
///
/// Run the unit tests.
///
public void RunAsync()
{
// Ensure there's an interface to display the test results.
if (this.Reporter == null)
{
throw new ArgumentNullException("Reporter");
}
// Setup the progress/failure counters
this.Progress = 0;
this.Failures = 0;
// Save the test setting changes
this.Settings.Save();
// Filter out any test methods based on the current settings
FilterTests();
// Write out the test status message which may be modified by the
// filters
Reporter.Status(this.Settings.TestRunStatusMessage);
// Enumerators that track the current group and method to execute
// (which allows reentrancy into the test loop below to resume at
// the correct location).
IEnumerator groups = this.Groups.OrderBy(g => g.Name).GetEnumerator();
IEnumerator methods = null;
// Keep a reference to the current group so we can pass it to the
// Reporter's EndGroup (we don't need one for the test method,
// however, because we close over in the continuation).
TestGroup currentGroup = null;
// Setup the UI
this.Reporter.StartRun(this);
// The primary test loop is a "recursive" closure that will pass
// itself as the continuation to async tests.
//
// Note: It's really important for performance to note that any
// calls to testLoop only occur in the tail position.
Action testLoop = null;
testLoop =
() =>
{
if (methods != null && methods.MoveNext())
{
// If we were in the middle of a test group and there
// are more methods to execute, let's move to the next
// test method.
// Update the progress
this.Progress++;
Reporter.Progress(this);
// Start the test method
Reporter.StartTest(methods.Current);
if (methods.Current.Excluded)
{
// Ignore excluded tests and immediately recurse.
Reporter.EndTest(methods.Current);
testLoop();
}
else
{
// Execute the test method
methods.Current.Test.Start(
new ActionContinuation
{
OnSuccess = () =>
{
// Mark the test as passing, update the
// UI, and continue with the next test.
methods.Current.Passed = true;
Reporter.EndTest(methods.Current);
testLoop();
},
OnError = (message) =>
{
// Mark the test as failing, update the
// UI, and continue with the next test.
methods.Current.Passed = false;
methods.Current.ErrorInfo = message;
this.Failures++;
Reporter.Error(message);
Reporter.EndTest(methods.Current);
testLoop();
}
});
}
}
else if (groups.MoveNext())
{
// If we've finished a test group and there are more,
// then move to the next one.
// Finish the UI for the last group.
if (currentGroup != null)
{
Reporter.EndGroup(currentGroup);
currentGroup = null;
}
// Setup the UI for this next group
currentGroup = groups.Current;
Reporter.StartGroup(currentGroup);
// Get the methods and immediately recurse which will
// start executing them.
methods = groups.Current.Methods.OrderBy(m => m.Name).GetEnumerator();
testLoop();
}
else
{
// Otherwise if we've finished the entire test run
// Finish the UI for the last group and update the
// progress after the very last test method.
Reporter.EndGroup(currentGroup);
Reporter.Progress(this);
// Finish the UI for the test run.
Reporter.EndRun(this);
// Send the test results if there's a server waiting
// for them.
if (!string.IsNullOrEmpty(this.Settings.TestResultsServerUrl))
{
SendTestResults();
}
}
};
// Start running the tests
testLoop();
}
///
/// Send results from the test run to the TestResultsServerUrl.
///
private void SendTestResults()
{
// TODO: Dump out the test results in TRX format
// Create an XML document describing the test run
XDocument results = new XDocument(
new XElement("TestRun",
new XAttribute("Count", Count),
new XAttribute("Failures", Failures),
Groups.SelectMany(group =>
group.Methods.Where(method => !method.Passed).Select(method =>
new XElement("Failure",
new XAttribute("Group", group.Name),
new XAttribute("Method", method.Name),
new XAttribute("Error", method.ErrorInfo)))
)));
// Post the results to the TestResultsServerUrl
HttpClient client = new HttpClient();
HttpContent content = new StringContent(results.ToString());
client.PostAsync(this.Settings.TestResultsServerUrl, content).Wait();
}
}
}
================================================
FILE: sdk/Javascript/test/framework/TestMethod.cs
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
namespace Microsoft.Azure.Zumo.Win8.Test
{
///
/// An individual test method to be executed.
///
public sealed class TestMethod
{
///
/// Initializes a new instance of the TestMethod class.
///
public TestMethod()
{
// WinJS is unhappy if we attempt to get a null string
this.Name = string.Empty;
this.Description = string.Empty;
this.ExcludeReason = string.Empty;
this.Tags = new List();
this.ErrorInfo = string.Empty;
}
///
/// Gets or sets the name of the test method.
///
public string Name { get; set; }
///
/// Gets or sets a more detailed description of the test method.
///
public string Description { get; set; }
///
/// Gets or sets a value indicating whether the test should be excluded
/// from execution.
///
public bool Excluded { get; private set; }
///
/// Gets or sets the reason the test was excluded (usually referencing
/// a known bug or work item).
///
public string ExcludeReason { get; private set; }
///
/// Gets the list of tags associated with this test method.
///
public IList Tags { get; private set; }
///
/// The test action to execute. This could be sync or async. Any
/// exceptions raised by invoking the test will be considered a test
/// failure.
///
public IAsyncExecution Test { get; set; }
///
/// Gets or sets a value indicating whether the test execution passed.
///
public bool Passed { get; set; }
///
/// Gets or sets any error information associated with a failing test.
///
public string ErrorInfo { get; set; }
///
/// Exclude the test method.
///
///
/// The reason for excluding the test method.
///
public void Exclude(string reason)
{
Excluded = true;
ExcludeReason = reason ?? "";
}
}
}
================================================
FILE: sdk/Javascript/test/framework/TestSettings.cs
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using Windows.Data.Json;
using Windows.Storage;
namespace Microsoft.Azure.Zumo.Win8.Test
{
///
/// Defines settings for the current test pass that can be provided via
/// a test application, passed to test filters, etc.
///
public sealed class TestSettings
{
///
/// Initializes a new instance of the TestSettings class.
///
public TestSettings()
{
this.TestRunStatusMessage = "Test Run";
this.TestResultsServerUrl = "";
this.BreakOnStart = true;
this.TagExpression = "";
this.Custom = new Dictionary();
// Load the test settings
this.Load();
}
///
/// Gets or sets a string containing the test run status message.
///
public string TestRunStatusMessage { get; set; }
///
/// Gets or sets a URL where test results are posted.
///
///
/// This is passed to the test application as an initialization
/// parameter and is used to enable test runs from the build. The test
/// launcher used by the build will create a simple web server (at this
/// URL) to listen for the posted test results.
///
public string TestResultsServerUrl { get; set; }
///
/// Gets or sets a value indicating whether the harness should break
/// before executing (so a debugger can be attached).
///
public bool BreakOnStart { get; set; }
///
/// Gets or sets the tag expression used to filter the tests that we
/// will run.
///
public string TagExpression { get; set; }
///
/// Gets a dictionary of custom test settings that are specific to a
/// given application.
///
public IDictionary Custom { get; private set; }
///
/// Load the cached test settings.
///
public void Load()
{
// Try to get the cached settings
object text = null;
if (ApplicationData.Current.LocalSettings.Values.TryGetValue("TestSettings", out text))
{
JsonObject settings = null;
if (JsonObject.TryParse(text as string, out settings))
{
this.TagExpression = settings.GetNamedString("TagExpression");
JsonObject custom = settings.GetNamedObject("Custom");
foreach (string key in custom.Keys)
{
this.Custom[key] = custom.GetNamedString(key);
}
}
}
}
///
/// Save the cached test settings.
///
public void Save()
{
JsonObject settings = new JsonObject();
settings.SetNamedValue("TagExpression", JsonValue.CreateStringValue(this.TagExpression));
JsonObject custom = new JsonObject();
settings.SetNamedValue("Custom", custom);
foreach (KeyValuePair setting in this.Custom)
{
custom.SetNamedValue(setting.Key, JsonValue.CreateStringValue(setting.Value));
}
ApplicationData.Current.LocalSettings.Values["TestSettings"] = settings.Stringify();
}
}
}
================================================
FILE: sdk/Javascript/test/framework/WinJS/Formatter.cs
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
using System;
namespace Microsoft.Azure.Zumo.Win8.Test.WinJS
{
///
/// Utility to provide .NET string formatting to WinJS tests.
///
public static class Formatter
{
///
/// Format a string.
///
/// The format specifier.
/// Format argument.
/// The formatted string.
public static string Format(string format, object arg)
{
return string.Format(format, arg);
}
///
/// Format a string.
///
/// The format specifier.
/// Format argument.
/// Format argument.
/// The formatted string.
public static string Format(string format, object arg0, object arg1)
{
return string.Format(format, arg0, arg1);
}
///
/// Format a string.
///
/// The format specifier.
/// Format argument.
/// Format argument.
/// Format argument.
/// The formatted string.
public static string Format(string format, object arg0, object arg1, object arg2)
{
return string.Format(format, arg0, arg1, arg2);
}
///
/// Format a string.
///
/// The format specifier.
/// Format argument.
/// Format argument.
/// Format argument.
/// Format argument.
/// The formatted string.
public static string Format(string format, object arg0, object arg1, object arg2, object arg3)
{
return string.Format(format, arg0, arg1, arg2, arg3);
}
///
/// Format a string.
///
/// The format specifier.
/// Format argument.
/// Format argument.
/// Format argument.
/// Format argument.
/// Format argument.
/// The formatted string.
public static string Format(string format, object arg0, object arg1, object arg2, object arg3, object arg4)
{
return string.Format(format, arg0, arg1, arg2, arg3, arg4);
}
}
}
================================================
FILE: sdk/Javascript/test/framework/WinJS/MessageEventArgs.cs
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
using System;
namespace Microsoft.Azure.Zumo.Win8.Test.WinJS
{
///
/// Event arguments used to provide messages form the WinJS TestReporter.
///
public sealed class MessageEventArgs
{
///
/// Gets or sets the message.
///
public string Message { get; set; }
}
}
================================================
FILE: sdk/Javascript/test/framework/WinJS/PromiseAsyncExecution.cs
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
using System;
namespace Microsoft.Azure.Zumo.Win8.Test.WinJS
{
///
/// Represents a WinJS async operation that can be given a continuation to
/// invoke when the async operation has completed (either successfully or
/// with an error).
///
///
/// Given that we can't directly invoke WinJS code, we also use this class
/// for synchronous operations and make sure everything works fine if we
/// return immediately.
///
public sealed class PromiseAsyncExecution : IAsyncExecution
{
///
/// Event used to execute the WinJS test action.
///
///
/// We can't pass a WinJS function as a delegate via WinRT, so we're
/// hacking around that by creating a stub which will wrap Execute and
/// invoke the desired function.
///
public event EventHandler Execute;
///
/// Start the async WinJS operation.
///
///
/// Continuation that should be invoked when the async operation has
/// completed.
///
public void Start(IContinuation continuation)
{
EventHandler handler = this.Execute;
if (handler != null)
{
try
{
// Invoke the WinJS operation by raising the Execute event
handler(this, new PromiseAsyncExecutionEventArgs(continuation));
}
catch (Exception ex)
{
// In the event the operation is actually sync, we'll catch
// any errors now and pass them to the error continuation.
continuation.Error(ex.ToString());
}
}
}
}
}
================================================
FILE: sdk/Javascript/test/framework/WinJS/PromiseAsyncExecutionEventArgs.cs
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
using System;
namespace Microsoft.Azure.Zumo.Win8.Test.WinJS
{
///
/// Event arguments that wrap a continuation to be invoked when an async
/// operation completes.
///
public sealed class PromiseAsyncExecutionEventArgs
{
///
/// The continuation to invoke when the operation completes.
///
private IContinuation continuation;
///
/// Always throw an InvalidOperationException.
///
///
/// We're required provide a parameterless constructor for types
/// exposed via WinMD even if that type will never be instantiated on
/// the other side of the boundary.
///
public PromiseAsyncExecutionEventArgs()
{
throw new InvalidOperationException();
}
///
/// Initializes a new instance of the PromiseAsyncExecutionEventArgs
/// class.
///
///
/// The continuation to be invoked when the async operation completes.
///
public PromiseAsyncExecutionEventArgs(IContinuation continuation)
{
if (continuation == null)
{
throw new ArgumentNullException("continuation");
}
this.continuation = continuation;
}
///
/// Invoke the continuation from a successful async operation.
///
public void Complete()
{
this.continuation.Success();
}
///
/// Invoke the continuation from a failing async operation.
///
/// The error message.
public void Error(string message)
{
this.continuation.Error(message);
}
}
}
================================================
FILE: sdk/Javascript/test/framework/WinJS/TestReporter.cs
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
using System;
namespace Microsoft.Azure.Zumo.Win8.Test.WinJS
{
///
/// Defines the interface used to report test results in a WinJS test
/// runner.
///
///
/// This class is a hack. WinJS types can't implement interfaces, so we're
/// going to instead define an event for each interface method that we can
/// invoke.
///
public sealed class TestReporter : ITestReporter
{
///
/// The test run started.
///
public event EventHandler ExecuteStartRun;
///
/// Update the test run progress.
///
public event EventHandler ExecuteProgress;
///
/// The test run finished.
///
public event EventHandler ExecuteEndRun;
///
/// The test group started is about to start executing its tests.
///
public event EventHandler ExecuteStartGroup;
///
/// The test group has finished executing its tests.
///
public event EventHandler ExecuteEndGroup;
///
/// The test method is about to be executed.
///
public event EventHandler ExecuteStartTest;
///
/// The test method has finished executing.
///
public event EventHandler ExecuteEndTest;
///
/// A message has been logged.
///
public event EventHandler ExecuteLog;
///
/// An error has been raised.
///
public event EventHandler ExecuteError;
///
/// The status has been changed.
///
public event EventHandler ExecuteStatus;
///
/// Raise an event.
///
/// The event arguments type.
/// The event handler to invoke.
/// The event arguments.
private void RaiseEvent(EventHandler handler, T args)
{
if (handler != null)
{
handler(this, args);
}
}
///
/// The test run started.
///
/// The test harness.
public void StartRun(TestHarness harness)
{
this.RaiseEvent(this.ExecuteStartRun, harness);
}
///
/// Update the test run progress.
///
///
/// The test harness (which contains Progress, Error, and Count
/// properties).
///
public void Progress(TestHarness harness)
{
this.RaiseEvent(this.ExecuteProgress, harness);
}
///
/// The test run finished.
///
///
/// The test harness (which contains Error and Count properties).
///
public void EndRun(TestHarness harness)
{
this.RaiseEvent(this.ExecuteEndRun, harness);
}
///
/// The test group started is about to start executing its tests.
///
/// The test group.
public void StartGroup(TestGroup group)
{
this.RaiseEvent(this.ExecuteStartGroup, group);
}
///
/// The test group has finished executing its tests.
///
/// The test group.
public void EndGroup(TestGroup group)
{
this.RaiseEvent(this.ExecuteEndGroup, group);
}
///
/// The test method is about to be executed.
///
/// The test method.S
public void StartTest(TestMethod test)
{
this.RaiseEvent(this.ExecuteStartTest, test);
}
///
/// The test method has finished executing.
///
/// The test method.
public void EndTest(TestMethod test)
{
this.RaiseEvent(this.ExecuteEndTest, test);
}
///
/// A message has been logged.
///
/// The message.
public void Log(string message)
{
this.RaiseEvent(this.ExecuteLog, new MessageEventArgs { Message = message });
}
///
/// An error has been raised.
///
/// Information about the error.
public void Error(string errorDetails)
{
this.RaiseEvent(this.ExecuteError, new MessageEventArgs { Message = errorDetails });
}
///
/// The status has been updated.
///
/// The status message.
public void Status(string status)
{
this.RaiseEvent(this.ExecuteStatus, new MessageEventArgs { Message = status });
}
}
}
================================================
FILE: sdk/Javascript/test/web/Microsoft.Azure.Zumo.Web.Test.csproj
================================================
$(MSBuildProjectDirectory)\..\..\toolsDebugAnyCPU2.0{5AA504E2-10A2-4179-9645-47E5CF857DDF}{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}LibraryPropertiesMicrosoft.Azure.Zumo.Web.TestMicrosoft.Azure.Zumo.Web.Testv4.5truetruefullfalsebin\DEBUG;TRACEprompt4pdbonlytruebin\TRACEprompt4Web.configWeb.config10.0$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)truebin\DEBUG;TRACEfullAnyCPUpromptMinimumRecommendedRules.rulesetTrueTrue47631/http://localhost:21123/FalseFalseFalse
CreateTestLibrary;
$(BuildDependsOn);
================================================
FILE: sdk/Javascript/test/web/Tests.library
================================================
================================================
FILE: sdk/Javascript/test/web/Web.Debug.config
================================================
================================================
FILE: sdk/Javascript/test/web/Web.Release.config
================================================
================================================
FILE: sdk/Javascript/test/web/Web.config
================================================
================================================
FILE: sdk/Javascript/test/web/css/styles.css
================================================
body {
font-family: Arial;
}
#test-config {
margin-bottom: 1em;
display: none;
}
#edit-test-config {
position: absolute;
right: 20px;
top: 16px;
font-size: 16px;
padding: 3px 16px;
}
================================================
FILE: sdk/Javascript/test/web/generated/.gitignore
================================================
*
!.gitignore
================================================
FILE: sdk/Javascript/test/web/index.html
================================================
Zumo Web Client Tests
================================================
FILE: sdk/Javascript/test/web/js/TestClientHelper.js
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
(function (global) {
// This file provides global.$getClient, which the test code uses when trying to make requests to the runtime.
// It also allows you to configure the URL of the runtime that it will talk to.
// Note: Implementing this without jQuery (or similar DOM library) to ensure
// that tests don't inadvertently start depending on it
global.$getClient = function () {
return new global.WindowsAzure.MobileServiceClient(clientUriElem.value, "dummy-app-key");
};
var configureButtonElem = document.getElementById("edit-test-config"),
configureFormElem = document.getElementById("test-config"),
clientUriElem = document.getElementById("runtime-uri"),
defaultClientUri = "http://localhost:11926/";
// Try to recover client URI from querystring
clientUriElem.value = parseQueryString()[clientUriElem.name] || defaultClientUri;
configureButtonElem.onclick = function () {
configureFormElem.style.display = "block";
configureButtonElem.style.display = "none";
};
function parseQueryString() {
var href = global.window.location.href,
queryStartPos = href.indexOf("?"),
query = queryStartPos >= 0 ? href.substring(queryStartPos + 1) : null,
tokens = query ? query.split("&") : [],
result = {},
tokenIndex,
pair;
for (tokenIndex = 0; tokenIndex < tokens.length; tokenIndex++) {
pair = tokens[tokenIndex].split("=");
if (pair.length === 2) {
result[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
}
}
return result;
}
})(this);
================================================
FILE: sdk/Javascript/test/web/js/TestFrameworkAdapter.js
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
(function (global, qunit, undefined) {
// This file allows our JavaScript client tests to be run in a browser via QUnit
// ------------------------------------------------------------------------------
// Top-level test framework APIs invoked by our tests
global.$test = function (testName) {
return new Test(testName);
};
global.$testGroup = function (groupName /*, test1, test2, ... */) {
var testsArray = arguments.length > 1 ? Array.prototype.slice.call(arguments, 1) : null;
return new TestGroup(groupName, testsArray);
};
global.$assert = {
isTrue: qunit.ok,
isFalse: function (value, message) { qunit.ok(!value, message); },
isNull: function (value, message) {
// Our tests treat null and undefined as if they were the same, because part of the
// WinJS test framework is written in .NET where there isn't a concept of undefined.
qunit.ok(value === null || value === undefined, message);
},
isNotNull: function (value, message) {
// As above, regard null and undefined as the same thing
qunit.ok(value !== null && value !== undefined, message);
},
areEqual: qunit.equal,
areNotEqual: qunit.notEqual,
fail: function (message) { qunit.ok(false, message); },
contains: function(str, substr, message) {
message = message || (str + " should contain " + substr);
qunit.ok((str || "").indexOf(substr) >= 0, message);
}
};
global.$assertThrows = function (action, verify, message) {
var thrown = true;
try {
action();
thrown = false;
} catch (ex) {
if (verify) {
verify(ex);
}
}
if (!thrown) {
$assert.fail(message || 'Should have failed!');
}
};
global.$chain = function () {
///
/// Given a list of functions that return promises, return a promise that
/// will chain them all together sequentially.
///
var actions = Array.prototype.slice.call(arguments);
return new global.Promises.Promise(function (complete, err) {
var error = function (ex) {
err(ex.responseText || JSON.stringify(ex));
};
var exec = function (prev) {
if (actions.length > 0) {
var next = actions.shift();
try {
var result = next(prev);
if (result) {
result.then(function (results) {
exec(results);
}, error);
} else if (actions.length === 0) {
complete();
} else {
error('$chain expects all actions except the last to return another Promise');
}
} catch (ex) {
error(ex);
}
} else {
complete();
}
};
exec();
});
};
global.$log = function (message) {
if (global.console) {
global.console.log(message);
}
};
global.$fmt = function (formatString /*, arg0, arg1, ... */) {
var positionalArgs = Array.prototype.slice.call(arguments, 1),
index;
for (index = 0; index < positionalArgs.length; index++) {
formatString = formatString.replace("{" + index + "}", positionalArgs[index]);
}
return formatString;
};
// ------------------------------------------------------------------------------
// Test represents a single test
function Test(testName) {
this.testName = testName;
this.tags = [];
}
Test.prototype.exclude = function () {
this.isExcluded = true;
return this;
};
Test.prototype.check = function (testFunc) {
this.testFunc = testFunc;
return this;
};
Test.prototype.checkAsync = function (testFunc) {
this.isAsync = true;
return this.check(testFunc);
};
Test.prototype.exec = function () {
if (this._shouldExclude()) {
return;
}
var self = this;
qunit.test(this.testName, function () {
qunit.ok(!!self.testFunc, "Test function was supplied");
var result = self.testFunc();
if (self.isAsync) {
qunit.ok(typeof result.then === "function", "Async test returned a promise");
qunit.stop();
result
.then(qunit.start, function (err) {
qunit.start();
qunit.ok(false, err && err.exception || err);
});
}
});
};
Test.prototype.tag = function (tagText) {
this.tags.push(tagText);
return this;
};
Test.prototype._shouldExclude = function () {
return this.isExcluded || this._hasTag("exclude-web");
};
Test.prototype._hasTag = function (tagText) {
// Can't use Array.prototype.indexOf because old IE doesn't have it
for (var i = 0; i < this.tags.length; i++) {
if (this.tags[i] === tagText) {
return true;
}
}
return false;
};
// These functions are not used in our browser tests - they are ignored
Test.prototype.functional = function () { return this; };
Test.prototype.description = function () { return this; };
// ------------------------------------------------------------------------------
// TestGroup represents a collection of tests, or in QUnit terms, a "module"
function TestGroup(groupName, testsArray) {
this.groupName = groupName;
if (testsArray) {
this.tests.apply(this, testsArray);
}
}
TestGroup.prototype.functional = function () { return this; }; // Not used in browser - ignored
TestGroup.prototype.tests = function (/* test1, test2, ... */) {
var testsArray = Array.prototype.slice.call(arguments, 0);
qunit.module(this.groupName);
for (var i = 0; i < testsArray.length; i++) {
testsArray[i].exec();
}
return this;
};
})(this, this.QUnit);
================================================
FILE: sdk/Javascript/test/web/promiseTests/package.json
================================================
{
"name": "windowsazuremobileservices-promise-tests",
"description": "Runs promise-tests against the Mobile Services JavaScript client",
"version": "0.0.1",
"dependencies": {
"promises-aplus-tests": ">= 1.1.0"
}
}
================================================
FILE: sdk/Javascript/test/web/promiseTests/readme.txt
================================================
Domenic Denicola has written a test suite for Promises/A+ compliance: https://github.com/promises-aplus/promises-tests/
You can run that test suite against our Mobile Services Web SDK by running the following commands in this directory:
npm install
node test-promises.js
Why a separate testing system?
============================================
Although we could convert this test suite into the $testGroup/$test/$assert format needed for compatibility with
our other client tests, it's not completely trivial because these Node tests rely on a Node-specific mocking library
and in any case we would then lose the ability to upgrade easily to newer versions of the test suite.
================================================
FILE: sdk/Javascript/test/web/promiseTests/test-promises.js
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
// This adapter file tells promises-tests how to construct and resolve our promises. This is needed because
// construction/resolution isn't defined by Promises/A, and each implementation works differently.
var promiseTests = require("promises-aplus-tests"),
mobileServices = require("../js/MobileServices.Web.Internals"),
ensureNotNull = function (val) {
// Like WinJS, we don't support null/undefined errors, so transparently replace usage in tests with some dummy error value
return val === null || val === undefined ? {} : val;
},
adapter = {
fulfilled: function (value) {
return mobileServices.Platform.async(function (callback) {
callback(null, value);
})();
},
rejected: function (error) {
return mobileServices.Platform.async(function (callback) {
callback(ensureNotNull(error));
})();
},
pending: function () {
// Returns a promise that is still waiting, along with resolution callbacks
var capturedCallback,
promise = mobileServices.Platform.async(function (callback) {
capturedCallback = callback;
})();
return {
promise: promise,
fulfill: function (val) { capturedCallback(null, val); },
reject: function (err) { capturedCallback(ensureNotNull(err)); }
};
}
};
promiseTests(adapter, function () { /* Output goes to console */ });
================================================
FILE: sdk/Javascript/test/web/tests/unit/push.js
================================================
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
$testGroup('Push',
/* deleteRegistrationWithName */
$test('Push.apns success')
.description('Verify apns object can be retrieved')
.tag('apns')
.check(function () {
var client = new WindowsAzure.MobileServiceClient("http://www.test.com", "123456abcdefg");
client = client.withFilter(function (req, next, callback) {
$assert.fail('No http call should have been made');
callback(null, { status: 500, responseText: 'Bad Test!' });
});
try {
var apns = client.push.apns;
$assert.isTrue(typeof apns == "object");
$assert.isTrue(typeof apns.registerNative == "function");
$assert.isTrue(typeof apns.registerTemplate == "function");
$assert.isTrue(typeof apns.unregisterNative == "function");
$assert.isTrue(typeof apns.unregisterTemplate == "function");
$assert.isTrue(typeof apns.unregisterAll == "function");
} catch (e) {
$assert.fail('unexpected error');
}
}),
$test('apns.register uppercases token')
.description('Verify apns device token is uppercased in calls')
.tag('apns')
.check(function () {
var client = new WindowsAzure.MobileServiceClient("http://www.test.com", "123456abcdefg");
client = client.withFilter(function (req, next, callback) {
$assert.areEqual(req.url, 'http://www.test.com/push/registrations?platform=apns&deviceId=123456ABCDEFG');
callback(null, { status: 500, responseText: 'Stop the chain' });
});
return client.push.apns.registerNative('123456abcdefg').then(null, function (error) {
$assert.areEqual(error.response.responseText, 'Stop the chain');
});
}),
$test('Push.gcm success')
.description('Verify gcm object can be retrieved')
.tag('gcm')
.check(function () {
var client = new WindowsAzure.MobileServiceClient("http://www.test.com", "123456abcdefg");
client = client.withFilter(function (req, next, callback) {
$assert.fail('No http call should have been made');
callback(null, { status: 500, responseText: 'Bad Test!' });
});
try {
var gcm = client.push.gcm;
$assert.isTrue(typeof gcm == "object");
$assert.isTrue(typeof gcm.registerNative == "function");
$assert.isTrue(typeof gcm.registerTemplate == "function");
$assert.isTrue(typeof gcm.unregisterNative == "function");
$assert.isTrue(typeof gcm.unregisterTemplate == "function");
$assert.isTrue(typeof gcm.unregisterAll == "function");
} catch (e) {
$assert.fail('unexpected error');
}
})
);
================================================
FILE: sdk/Javascript/test/winJS/Microsoft.WindowsAzure.Mobile.WinJS.Test.jsproj
================================================
$(MSBuildProjectDirectory)\..\..\toolsBuildToolsAnyCPUBuildToolsARMBuildToolsx64BuildToolsx86DebugAnyCPUDebugARMDebugx64Debugx86ReleaseAnyCPUReleaseARMReleasex64Releasex8696b18d27-dff3-47a2-835b-ef1e6af1a39cWindows8.0en-USMicrosoft.Azure.Zumo.Windows.WinJS.Test_TemporaryKey.pfxF2898C88F4280EC05ED71A9D3C1A457722594B4BDesigner
CreateTestLibrary;
$(BuildDependsOn);
================================================
FILE: sdk/Javascript/test/winJS/Tests.library
================================================
================================================
FILE: sdk/Javascript/test/winJS/css/default.css
================================================
body {
overflow-y: scroll
}
#subHeader {
margin: 16px 24px 0px 24px;
}
#header {
margin: -8px 24px 8px 24px;
color: #0094ff;
}
#testStatus {
margin: 0px 24px;
color: #808080;
}
#testResults {
margin: 3px;
}
#footer {
display: none;
margin: 10px auto;
width: 80%;
}
#progress {
width: 100%;
}
#footerContent {
text-align: center
}
.testRunEndFailure {
color: #ff006e;
margin: 25px;
text-align: center;
}
.testRunEndSuccess {
color: #2a9e39;
margin: 25px;
text-align: center;
}
.testGroup {
margin-left: 20px;
margin-right: 20px;
padding-top: 10px;
border-bottom: 1px solid #F0F0F0;
}
.testMethod {
margin-left: 40px;
margin-right: 20px;
font-weight: normal;
}
.testMethodName {
display: inline-block;
min-width: 200px;
}
.testMethodNamePassed {
display: inline-block;
min-width: 200px;
color: #2a9e39;
}
.testMethodNameFailed {
display: inline-block;
min-width: 200px;
color: #ff006e;
}
.testMethodNameIgnored {
display: inline-block;
min-width: 200px;
color: gray;
text-decoration: line-through;
}
.testMethodDescription {
color: gray;
margin-left: 5px;
}
.testMethodLog {
margin-left: 60px;
margin-right: 20px;
font-size: 80%;
}
.testMethodError {
margin-left: 60px;
margin-right: 20px;
color: #ff006e;
}
.testMethodIgnore {
margin-left: 60px;
margin-right: 20px;
color: gray;
font-size: 80%;
}
================================================
FILE: sdk/Javascript/test/winJS/default.html
================================================
Microsoft.Azure.Zumo.Windows.WinJS.Test