Categories
Azure Microsoft

Take control of multi-platform push notifications with Azure Notification Hubs

Msdevmtl Meetup at Microsoft Montreal (2000 McGill College Ave, Suite 550) Monday, March 20, 2017 6:30 PM

Thank you for attending this presentation!

You can find the source code of the demo project on GitHub:

 

As a reminder, the project is built around the following technologies:

  • Azure Notification Hubs
  • Azure WebJobs
  • ASP.NET Web API
  • Xamarin Android

 

Download the PowerPoint presentation in French below:

 

Please feel free to contact me if you have any question about the presentation or the project.


Join me March 20, 2017 6:30 PM at Microsoft Montreal for a presentation of Azure Notification Hubs!

 

Together we’ll see how Azure Notification Hubs can make your life easier by giving you the ability to easily send millions of messages across multiple platforms.

In this 60 minutes session, we will discover Azure Notification Hubs through a presentation which will show you the main lines of the product, how to set it up with the Azure portal but also via ARM template, then ending with a practical part and a concrete demonstration of use.

 

Please note that in the same evening François (Frank) Boucher will give a presentation about Azure Functions!

Categories
App Service Azure Microsoft

Deploying a web app and an Azure SQL database with ARM template without providing any password

Do you really need to provide a database password in the parameters of your ARM template?

Using an ARM template to create a Website and a SQL Database together is an easy task with Azure. However, each time you need to provide an SQL Admin username and password.

In a previous article, we’ve discovered how to automatically generate a password for an Azure SQL database with ARM template.

Today, following this article, we will learn how to deploy a web app in Azure App Service and an Azure SQL Database with ARM template without providing any password. Our ARM template will be created in a new Azure Resource Group deployment project in Visual Studio.

 

Creation

Let’s declare the parameters of the ARM template:

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "databaseCollation": {
      "type": "string",
      "defaultValue": "SQL_Latin1_General_CP1_CI_AS"
    },
    "databaseEdition": {
      "type": "string",
      "defaultValue": "Basic",
      "allowedValues": [
        "Basic",
        "Standard",
        "Premium"
      ]
    },
    "databaseMaxSizeBytes": {
      "type": "string",
      "defaultValue": "1073741824"
    },
    "databaseRequestedServiceObjectiveName": {
      "type": "string",
      "defaultValue": "Basic",
      "allowedValues": [
        "Basic",
        "S0",
        "S1",
        "S2",
        "P1",
        "P2",
        "P3"
      ],
      "metadata": {
        "description": "Describes the performance level for Edition"
      }
    },
    "hostingPlanSkuName": {
      "type": "string",
      "defaultValue": "F1",
      "allowedValues": [
        "F1",
        "D1",
        "B1",
        "B2",
        "B3",
        "S1",
        "S2",
        "S3",
        "P1",
        "P2",
        "P3",
        "P4"
      ],
      "metadata": {
        "description": "Describes plan's pricing tier and instance size. Check details at https://azure.microsoft.com/en-us/pricing/details/app-service/"
      }
    },
    "hostingPlanSkuCapacity": {
      "type": "int",
      "defaultValue": 1,
      "minValue": 1,
      "metadata": {
        "description": "Describes plan's instance count"
      }
    }
  }
  ...
}
  • databaseCollation: the collation of the database, by default SQL_Latin1_General_CP1_CI_AS.
  • databaseEdition: the edition of the database, by default Basic.
  • databaseMaxSizeBytes: the size of database, by default 1GB.
  • databaseRequestedServiceObjectiveName: the pricing tier of the database, by default Basic.
  • hostingPlanSkuName: the pricing tier of the hosting plan, by default F1.
  • hostingPlanSkuCapacity: the hosting plan’s instance count, by default 1.

 

Now we will declare the variables of the ARM template:

{
  ...
  "variables": {
    "databaseName": "[concat('mydb', uniqueString(resourceGroup().id, 'E931CAC0-7259-4FA1-80B4-BD47CBA4E040'))]",
    "hostingPlanName": "[concat('myhostingPlan', uniqueString(resourceGroup().id))]",
    "sqlserverAdminLogin": "[concat('l', uniqueString(resourceGroup().id, '9A08DDB9-95A1-495F-9263-D89738ED4205'))]",
    "sqlserverAdminPassword": "[concat('P', uniqueString(resourceGroup().id, '224F5A8B-51DB-46A3-A7C8-59B0DD584A41'), 'x', '!')]",
    "sqlserverName": "[concat('mysqlserver', uniqueString(resourceGroup().id))]",
    "websiteName": "[concat('mywebsite', uniqueString(resourceGroup().id, '274ACF17-FF18-4DB2-B3A8-AABCA4CB7D54'))]"
  }
  ...
}

The variables were already described in the previous article, but here what we can pay attention to:

  • We use a lot the ARM template function uniqueString allowing us to create a deterministic hash string based on the values provided as parameters.
  • We are able to create a random database name, admin login, admin password, SQL server name.
  • The names will be unique for the resource group.
  • To make sure that we are compliant with the Azure SQL database policy “Your password must contain characters from three of the following categories – English uppercase letters, English lowercase letters, numbers (0-9), and non-alphanumeric characters (!, $, #, %, etc.)”, we insert one character for each category before and after the unique string.

 

And to finish we will declare the resources of the ARM template:

{
  ...
  "resources": [
    {
      "apiVersion": "2015-08-01",
      "name": "[variables('hostingPlanName')]",
      "type": "Microsoft.Web/serverfarms",
      "location": "[resourceGroup().location]",
      "properties": {
        "name": "[variables('hostingPlanName')]"
      },
      "sku": {
        "name": "[parameters('hostingPlanSkuName')]",
        "capacity": "[parameters('hostingPlanSkuCapacity')]"
      },
      "tags": {
        "displayName": "HostingPlan"
      }
    },
    {
      "apiVersion": "2014-04-01-preview",
      "name": "[variables('sqlserverName')]",
      "type": "Microsoft.Sql/servers",
      "location": "[resourceGroup().location]",
      "properties": {
        "administratorLogin": "[variables('sqlserverAdminLogin')]",
        "administratorLoginPassword": "[variables('sqlserverAdminPassword')]"
      },
      "tags": {
        "displayName": "SqlServer"
      },
      "resources": [
        {
          "apiVersion": "2014-04-01-preview",
          "name": "[variables('databaseName')]",
          "type": "databases",
          "location": "[resourceGroup().location]",
          "dependsOn": [
            "[concat('Microsoft.Sql/servers/', variables('sqlserverName'))]"
          ],
          "properties": {
            "edition": "[parameters('databaseEdition')]",
            "collation": "[parameters('databaseCollation')]",
            "maxSizeBytes": "[parameters('databaseMaxSizeBytes')]",
            "requestedServiceObjectiveName": "[parameters('databaseRequestedServiceObjectiveName')]"
          },
          "tags": {
            "displayName": "Database"
          }
        },
        {
          "apiVersion": "2014-04-01-preview",
          "name": "AllowAllWindowsAzureIps",
          "type": "firewallrules",
          "location": "[resourceGroup().location]",
          "dependsOn": [
            "[resourceId('Microsoft.Sql/servers', variables('sqlserverName'))]"
          ],
          "properties": {
            "startIpAddress": "0.0.0.0",
            "endIpAddress": "0.0.0.0"
          }
        }
      ]
    },
    {
      "apiVersion": "2015-08-01",
      "name": "[variables('websiteName')]",
      "type": "Microsoft.Web/sites",
      "location": "[resourceGroup().location]",
      "dependsOn": [
        "[concat('Microsoft.Web/serverFarms/', variables('hostingPlanName'))]"
      ],
      "properties": {
        "name": "[variables('websiteName')]",
        "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]"
      },
      "tags": {
        "[concat('hidden-related:', resourceGroup().id, '/providers/Microsoft.Web/serverfarms/', variables('hostingPlanName'))]": "empty",
        "displayName": "Website"
      },
      "resources": [
        {
          "apiVersion": "2015-08-01",
          "name": "connectionstrings",
          "type": "config",
          "dependsOn": [
            "[resourceId('Microsoft.Web/sites', variables('websiteName'))]"
          ],
          "properties": {
            "MyDbConnectionString": {
              "value": "[concat('Data Source=tcp:', reference(concat('Microsoft.Sql/servers/', variables('sqlserverName'))).fullyQualifiedDomainName, ',1433;Initial Catalog=', variables('databaseName'), ';User Id=', variables('sqlserverAdminLogin'), '@', variables('sqlserverName'), ';Password=', variables('sqlserverAdminPassword'), ';')]",
              "type": "SQLServer"
            }
          }
        }
      ]
    }
  ]
  ...
}

Here we declare the website, the SQL Server and its database:

  • As you can notice, we are declaring the connection strings of the website.
  • We are setting the complete connection string MyDbConnectionString for our database using the generated password.

 

Example of use

The ARM template is now ready, let’s open a Windows PowerShell and try it:

.\Deploy-AzureResourceGroup.ps1 -ResourceGroupName 'MyResourceGroupName' -ResourceGroupLocation 'canadaeast' -TemplateFile '.\azuredeploy.json'

...

Resource Microsoft.Sql/servers/databases 'mysqlserverdprkifjzxpany/mydbodsrno26t2xnk' provisioning status is succeeded

If everything goes well, you should see the same kind of message as above.

 

To go further

If you check the application settings via the portal, the connection string will look like the following:

MyDbConnectionString = Data Source=tcp:mysqlserverdprkifjzxpany.database.windows.net,1433;Initial Catalog=mydbodsrno26t2xnk;User Id=lgjytuqjz44e7s@mysqlserverdprkifjzxpany;Password=Pxhhg2lv4jbx2qx!;

 

As no user needs to know the password, you could enforce the security by changing the password on every deployment using the deployment name in the ARM template function uniqueString. Change the password variable as following:

"sqlserverAdminPassword": "[concat('P', uniqueString(resourceGroup().id, deployment().name, '224F5A8B-51DB-46A3-A7C8-59B0DD584A41'), 'x', '!')]"

 

Summary

You can’t access the SQL database as you don’t know the generated password but the web app can access it and that’s what we want. Now via Entity Framework Code First for example, your web application would now be able to create the database tables.

We have seen how to create an ARM template that will deploy a web app and an Azure SQL database without providing any password.

 

You can download the example solution here:

Download full sources

Or

Browse the GitHub repository

 

Please feel free to comment or contact me if you have any question about this article.

Categories
Azure Microsoft

Passed Exam 70-532: Developing Microsoft Azure Solutions

Now is a good time to validate your Azure skills!

I’ve been developing with Azure for a while and this week I made the jump into passing my first Azure certification with Exam 70-532 in order to validate my skills.

 

Passing the exam and result

I scheduled an online proctored exam and after two and an half hours I successfully passed the exam at the first shot! The pool of questions is very large and case studies were interesting. Yes as often there are some tricky questions but overall it has been a great way to validate my knowledge.

Also if you jumped on the Azure train late and never had the opportunity to work with Cloud Services such as Web Role or Worker Role this want prevent you from passing this exam. As Azure is evolving every day, the exam was updated recently to reflect the new services. To maximize your chances I would advise you to at least know and understand Cloud Services.

 

Take advantage of the current offer

The current Azure certification offer is really interesting if you want to pass any of the following exam: 70-473, 70-475, 70-532, 70-533 and 70-534.

For USD $99 receive one voucher or three vouchers for USD $279. Each voucher will allow you to:

  • Pass one exam
  • Have one exam retake in case you fail your first attempt
  • Get the Microsoft Official Practice Test for the exam

Considering that a single exam itself is usually USD $165, this offer valid until 6/30/2017 is great if you want to validate your Azure skills!

 

Take advantage of the current offer

It’s always rewarding to get an exam, receive a badge and I encourage you to go ahead in validating your Azure knowledge.

 

Please feel free to comment or contact me if you have any question. Of course don’t ask me about to the content of the exam, as you know Non-Disclosure Agreement apply for Microsoft Certification Exams.