Showing posts sorted by relevance for query Deploy. Sort by date Show all posts
Showing posts sorted by relevance for query Deploy. Sort by date Show all posts

Deploy automatically a static website into an Azure Blob storage with Azure DevOps Pipeline

Static websites are lightning fast, and running them inside an Azure Blob Storage instead of a WebApp is incredibly economical (less than $1/ month). Does it mean you need to do everything manually? Absolutely not! In a previous post I explained how to automatically generated your static website using a Build Pipeline inside Azure DevOps. In this post, let's complete the CI-CD by creating a Release Pipeline to deploy it.

The Azure Resource Manager (ARM) Template


First thing first. If we want our release pipeline to deploy our website in Azure, we need first to be sure our Resources are available "up there." The best way to do this is by using an Azure Resource Manager (ARM template). I will use the same project started in the previous post, feel free to adapt to your structure or copy it from it.

Create a new file named deploy.json in the deployment folder. We need a simple storage account.

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "StorageName": {
            "type":"string",
            "defaultValue": "cloudenfrancaisv2",
            "maxLength": 24
        }
    },
    "variables": {},
    "resources": [
        {
            "type": "Microsoft.Storage/storageAccounts",
            "apiVersion": "2018-07-01",
            "name": "[parameters('StorageName')]",
            "location": "[resourceGroup().location]",
            "tags": {
                "displayName": "[parameters('StorageName')]"
            },
            "sku": {
                "name": "Standard_LRS"
            },
            "kind": "StorageV2"
        }
    ],
    "outputs": {}
}

I used a parameter (StorageName) to define the name of the storage account. This way I could have multiple pipelines deploying in different storages.

Not to make the ARM template accessible to the release pipeline we also need to publish it. The easiest way to do it is to add another Copyfile task in our azure-pipeline. Add this task just before the PublishBuildArtifacts.

- task: CopyFiles@2
displayName: 'Copy deployment content'
inputs: 
    SourceFolder: '$(Build.SourcesDirectory)/deployment'
    contents: '**\*' 
    targetFolder: $(Build.ArtifactStagingDirectory)/deployment
    cleanTargetFolder: true

Once you commit and push these changes, it will trigger a build. When done, the ARM template will be available, and we will be able to start working on the release pipeline.

The Release Pipeline


Navigate to the DevOps project created in the previous post. This time, create a new Release Pipeline. When asked, select an empty template, we will pick manually the tasks we need.

First, we need to define the trigger and where are our artifacts. Click on the thing at the left of the screen. Select the build projects and let's use the latest version of the artifact to our deployment.

To get a continuous deployment, you need to enable it by clicking on the lightning bolt and selecting the enabled button.

Now let's select our tasks. Click on the "+" sign to add new tasks. We need three of these: Azure Resource Group Deployment, Azure CLI, and Azure File Copy.



Task 1 - Azure Resource Group Deployment


The first one will be an Azure Resource Group Deployment. The will be used to deploy our ARM template and be sure that the resources are available in Azure.

To configure the ARM deployment we need to select the Azure subscription and authorize the pipeline to have access. Then you will need to specify the name of the resource group you will be deploying into; it's location and finally points where is the linked ARM template.


Task 2 - Azure CLI


The second one is an Azure CLI. As I am writing this post, it's not possible to enable the static website property of a storage account. Therefore we will execute an Azure CLI command to change that configuration. Once you picked the Azure subscription, select inline script and enter this Azure CLI command:

az storage blob service-properties update --account-name wyamfrankdemo --static-website  --index-document index.html

This will enable the static website property of the storage account named wyamfrankdemo, and set the default document to index.html.

Task 3 - Azure File Copy


The last task is an Azure File Copy to copy all our files from $(System.DefaultWorkingDirectory)/drop/drop/outpout to the $web container (in our Azure Blob storage). The container must be named $web, that's the name used by Azure for the static website.

Wrapping up


Once you are done configuring the Release Pipeline, it's time to save it and run it. After only a minute or two (this demo is pretty small) the blog should be available into Azure. To find your endpoint (aka URL) you can go into the portal.azure.com and look at the static website property of the blob storage that we just create.

In a video, please!


I also have a video of this post if you prefer.





Lecture de la semaine #6

 

from BluPointe Blog

“to read more about the filter attribute, see bit.ly/kMPBYB
“The list of built-in MVC filters can be found here: bit.ly/jSaD5N
“Profiling Your .NET Code : bit.ly/dDXWsF
“ - Guide to Improving Code Performance in .NET: Part I” by Satesh Arveti on C# Corner (bit.ly/gyImk9)
- Writing Efficient C and C Code Optimization” by Koushik Ghosh on Code Project (bit.ly/icnYEi)
- Writing High Performance .NET Code” by Juan A Rodriguez and Simonijt Dutta from Intel (intel.ly/fvweaP)”
“Deploy sites to Windows Azure in less than 30 seconds Enables deployments to multiple Web Role instances using Web Deploy Saves Web Deploy packages & IIS configuration in Windows Azure storage to provide durability A web administrator portal for managing web sites deployed to the role The ability to upload and manage SSL certificates Simple logging and diagnostics tools.”
“Installing the WAAWR is as easy as download, extract, buildme.cmd and you’re done.”

~ Franky

ClickOnce: The easy way to deploy the .Net applications

ClickOnce

The easy way to deploy the .Net applications

  1. Introduction
  2. The Application
  3. Deployment of an application
    • First deployment
  4. Installation
  5. Update
  6. Uninstalling the Application
  7. Examining the Application and Deployment Manifests
    • The Application Manifest
    • The Deployment Manifest
  8. Security
    • Sign the ClickOnce manifest
    • Security permissions
  9. Faqs
  10. Extra
    • Current Version
    • Update Detail
    • Updating manually
    • Downloading Files on Demand
  11. References

Introduction

ClickOnce is a new application deployment technology that makes deploying a Windows Forms based application as easy as deploying a web application.
ClickOnce applications can be deployed via web servers, file servers or CDs. A ClickOnce application can choose to be installed, meaning it gets start menu & add/remove program entries, or an app can simply be run and cached. ClickOnce can be configured in several ways to check automatically for application updates. Alternatively, applications can use the ClickOnce APIs (System.Deployment), to control when updates should happen.
Using ClickOnce requires that the target client already have the .NET Framework 2.0 installed. Visual Studio has made packaging and deploying the .NET Framework simpler than ever. Simply select what pre-requisites your application may have (e.g., the .NET Framework 2.0 and MDAC 9.0) and Visual Studio will generate a bootstrapper file that will automatically install all of the specified prerequisites when run. On the server side, ClickOnce needs only an HTTP 1.1 server or alternatively a file server.
So let’s start and build a simple application…

The Application

Create a simple windows base application named MyClickTest. Just put a label on the Form1 and set the text property equal to: “Version 1”. That all for the first version of our application.

image

 

Deployment of an application

First deployment

To start the publishing configuration you must go in the property of the project. You can right-click on the Project name [MyClickTest] in the Solution Explorer at the top right of the screen or in Menu | Project | MyClickTest Properties. Than in the tab Signing check the [Sign the ClickOnce manifest].
image
We must now define the Security level. For the moment, check the box which indicates that our application is "Full trust". By safety measure, it will be necessary to better avoid choosing this option; we will thus see a little later in this tutorial how to define these options of safety as well as possible.
image
Let go now to the greatest part: publication. In the Publish tab you can define the location of you’re publication. This location will specify if the application will by publish from a web site, a ftp site or by a share folder of a network.
In some scenarios, it may be important to first publish the application to a staging server before moving it to another server for deployment. While the Publishing Location text box specifies the location to which you'll publish the application, the Installation URL text box allows you to specify where the users should install your application. As an example, consider the following scenario:
When you publish the application using the above settings, the application will deploy to http://server1/ MyClickTest/. However, you will need to manually copy all of the files located in the folder mapped to http://server1/MyApp/ into the folder mapped to http://server2/MyClickTest/.
Users will then install the application from http://server2/MyClickTest/ (that is, through http://server2/ MyClickTest/index.htm). More importantly, the application will check for updates from http://server2/MyClickTest/ and not http://server1/MyClickTest/.
image
Also you define the installation mode. Does the application will be available online only (download every time) or the application can by available online and in offline mode, so install locally and available in the Start menu. Other configurations are available:
· Application Files: Here are listed all files associated with the projects. (Figure 1) image
Figure 1
· Prerequisites: Here you can specify the list of the applications must by install to run you’re application (Figure 2). The bootstrapper is very extensible and can be used to install 3rd party and custom pre-requisites.
image
Figure 2
To add our own prerequisite you need to have bootstrapper package. Once created boot strapper package then it will automatically included into prerequisite list. To generate bootstrapper can use “Bootstrapper Manifest Generator” tool. Follow the steps given below to add own bootstrapper using “Bootstrapper Manifest Generator” tool.(http://www.gotdotnet.com/workspaces/workspace.aspx?id=ddb4f08c-7d7c-4f44-a009-ea19fc812545)
  • Updates: Here you specify if the application will check for update on the server, when it will do (before or after the application start). (Figure 3). If you check for updates after the application has started, you can specify how often to check. The most frequent check you can perform is once per day.
image
Figure 3
To prevent users from running an older version of your application, you can specify the minimum version required. This option is useful if you have just discovered a major bug in your application; to prevent users from rolling back to the previous version after the update, you can set the current version number as the minimum required version.
By default, your application will check for updates from locations in the following order:
1. Update location (if specified in this window).
2. Installation URL (if specified in the Publish tab of the project properties).
3. Publish location.
 
  • Options: You can specify various information (Figure 4).
 
image
Figure 4
Once all information is completed click the button "Publish Wizard" (also available in menu [Build] or, in the [Solution Explorer], by right clicking) that will start the Installation Wizard to configure the ClickOnce installation.

The Publish Wizard enables you to configure all the options necessary to the deployment of the application.
clip_image018
Again you can specify the location of the publication…
image
… the installation mode ( online or offline)…
image
Because all the information is already specified in the previous screen press the [Finish] button will be the same.
By clicking the button a new web page is automatically create to publish the application. You can see the page by tipping the web address specified previously (http://localhost/MyClickTest/index.htm)
image

Installation

To install the application just click the [Install] button. That will launch the installation of the application on the station and one sees well the checking of the presence of update, right before launching:
image
image
Now you’re application is available in the Start menu.
image
Update
Now get back to Visual Studio and charge the label to Version 2. In the Build menu (or, in the [Solution Explorer], by right clicking) re-publish the application. From the Start menu launch the application. A popup should be display asking you to update the version on you is local machine.
image
Now you should see Version 2 in the label.

Uninstalling the Application

To uninstall a ClickOnce application, users can go to the Control Panel and launch the "Add or Remove Programs" application. In the "Change or Remove Programs" section, users then select the application to uninstall and click the Change/Remove button.
If the application has been updated at least once, users will see the option "Restore the application to its previous state," which allows users to roll back the application to its previous version. Users then select the option "Remove the application from this computer" to uninstall the application.
image

Examining the Application and Deployment Manifests

When you use the Publish Wizard in ClickOnce, Visual Studio will publish your application to the URL you have indicated. For example, if you indicated http://localhost/MyClickTest/ as the publishing directory and you mapped the virtual directory MyClickTest to the local path C:\Inetpub\wwwroot\MyClickTest, two types of files will be created under the C:\Inetpub\wwwroot\MyClickTest directory:
· The application manifest
· The deployment manifest
The Application Manifest
When you publish your application, a folder and four files are automatically generated in the publishing directory. They are:
· A folder containing the deployment files (MyClickTest_1_0_0_0; see next section).
· An application manifest MyClickTest.application. The index.htm file points to this application (by default is publish.htm).
· A version-specific application manifest; for example, MyClickTest_1_0_0_0.application.
· A index.htm (publish.htm) web page containing instructions on how to install the application.
· A setup application (setup.exe).
image
The application manifest MyClickTest.application is an XML file that contains detailed information about the current application as well as its version number. It lets users know if they need to update application.
When you re-publish your application, the contents of MyClickTest.application, publish.htm, and setup.exe will be modified, while one new version-specific application manifest (for example, MyClickTest_1_0_0_1.application) and a new folder (for example, MyClickTest_1_0_0_1) containing the new versions of deployment files will be created.
The Deployment Manifest
Locate the deployment manifest, MyClickTest.exe.manifest, in the C:\Inetpub\wwwroot\MyClickTest\MyClickTest _1_0_0_0 directory. It contains information about the application (such as dependencies and attached files). The MyClickTest.exe.deploy file is your application's executable. The other files and databases in the directory are used by your application. During installation, these files will be downloaded onto your users' machines.
image
Security
Sign the ClickOnce manifests
You have the possibility of signing the manifest your ClickOnce application, like signing your assembly NET.
With Visual Studio 2005, you don’t need anymore to use command prompt tool. In the tab [Signing] (of the page of properties of your project) just check the box [Sign the assembly] and via the drop-down menu, pick a option to create a new file “snk”.
You also have the possibility of signing the manifest your ClickOnce application, by using a certificate of safety. Use a certificate already installed (button [Select from Blind]), or import your certificate (button [Select from File]).
Security permissions
A good safety is that which gives less possible freedoms, more precisely, that which gives simply the rights necessary. You can do it manually by choosing rights which you grant to your application or then, you can let Visual Studio do that for you.
Click on [Calculating the permissions]
image
Visual Studio then will analyze each line of your code in order to detect (according to your methods) the authorizations needed.
image
Faqs
 
Does "ClickOnce" download the entire application every-time I update it? 
No. “ClickOnce” only downloads the files and assemblies that have changed.
I want my application to be installed to a specific hard drive location, how can I achieve this?
The install location of "ClickOnce" application cannot be managed by the application. This is an important part of making "ClickOnce" applications safe, reversible, and easy to administer.
Can I use compression to make my application download faster? 
Yes, “ClickOnce” supports HTTP 1.1 compression. Simply enable this on your web server & the files “ClickOnce” downloads will be compressed.
Can I install a "ClickOnce" application per-machine?
No. All “ClickOnce” applications are installed per-user. Each user is totally isolated from one another and must install their own copy. If your application needs to be installed per-machine, you should use MSI.
Extra
A lot of functionality are available by the System.Deployment.Application reference.
Let present some of those. First see the interface.
image
Current Version
In the Form_load of the form let retrieve the information about the current version.
[code:c#;ln=on]
private void Form1_Load( object sender, EventArgs e){
    ApplicationDeployment oDeploy;
    // Check if the application is deploy by the ClickOnce chkClickDeploy.Checked = ApplicationDeployment.IsNetworkDeployed;
    if (ApplicationDeployment.IsNetworkDeployed) {
        // Because the application is a CLickOnce deployement there are some information
        // there are available lke the current version, the Location of this version update.
        oDeploy = ApplicationDeployment.CurrentDeployment;
        txtCurrentVersion.Text = oDeploy.CurrentVersion.ToString();
        txtCurrentServer.Text = oDeploy.UpdateLocation.ToString();
    }
    this.txtinstallFolder.Text = Environment.CurrentDirectory;
}[/code]
Update Detail
By clicking the button [Check Now] let check if a new release is available, and if yes then retrieve the information about that one.
[code:c#;ln=on]
private void btnCheck_Click(object sender, EventArgs e)
{
ApplicationDeployment oDeploy;
if (ApplicationDeployment.IsNetworkDeployed)
{
oDeploy = ApplicationDeployment.CurrentDeployment;
// Check if a newest version is available.
UpdateCheckInfo oInfoChecker = oDeploy.CheckForDetailedUpdate();
if (oInfoChecker.UpdateAvailable)
{
// If yes then retreive the latest version available
// (because you can jump a version). check if the version
// in mandatory and the size.
chkUpdateAvailable.Checked = oInfoChecker.UpdateAvailable;
txtLastVersion.Text = oInfoChecker.AvailableVersion.ToString();
chkUpdateMandatory.Checked = oInfoChecker.IsUpdateRequired;
txtLastVersionServer.Text = oDeploy.UpdateLocation.ToString();
txtUpdateSize.Text = oInfoChecker.UpdateSizeBytes.ToString();
}
else {
MessageBox.Show("No update available...");
}
}
}[/code]
Updating manually
By clicking the button [Update] the application will update to the latest version available. We can do it asynchronally or synchronally. The new version will take effect after to re-start the application.
[code:c#;ln=on]
private void btnUpdate_Click(object sender, EventArgs e)
{
ApplicationDeployment oDeploy;
if (ApplicationDeployment.IsNetworkDeployed)
{
oDeploy = ApplicationDeployment.CurrentDeployment;
UpdateCheckInfo oInfoChecker = oDeploy.CheckForDetailedUpdate();
if (oInfoChecker.UpdateAvailable)
{
if (optSynch.Checked){
oDeploy.Update();
MessageBox.Show("Update done successfully...");
}
else {
oDeploy.UpdateCompleted += new AsyncCompletedEventHandler(oDeploy_UpdateCompleted);
oDeploy.UpdateProgressChanged += new DeploymentProgressChangedEventHandler(oDeploy_UpdateProgressChanged);
oDeploy.UpdateAsync();
}
}
}
}
void oDeploy_UpdateProgressChanged(object sender, DeploymentProgressChangedEventArgs e)
{
this.toolStripProgressBar1.Value = e.ProgressPercentage;
}
void oDeploy_UpdateCompleted(object sender, AsyncCompletedEventArgs e)
{
MessageBox.Show("Update done successfully...");
}
private void btnReStart_Click(object sender, EventArgs e)
{
Application.Restart();
}
[/code] 
Downloading Files on Demand
If you have a large-size help file, this adds to the download time for your users. And if you have multiple help files in your application, then the entire application will also take longer to install. A better approach is to selectively download the help files as and when you need them. For example, you can set the help file to download after the application installs, when a user clicks on the Display Help button.
To specify that the help file be loaded as and when needed, you need to perform the following steps:
· In Visual Studio in the [Solution Explorer] add a text File: ClickHelp.txt.
· Get back in the Property of the Project in the tab [Publish]. Click on the button [Application Files]. Change the Publish Status of ClickHelp.txt to Include.
· Click the drop-down menu in the Download Group and select (New).
· Specify a name for the download group, such as: Help.
· Add a new button on the form. Then double-click on it to add this handler code.
[code:c#;ln=on]
private void button1_Click(object sender, EventArgs e)
{
ApplicationDeployment oDeploy;
// Check if the application is deploy by the ClickOnce
if(ApplicationDeployment.IsNetworkDeployed){
oDeploy = ApplicationDeployment.CurrentDeployment;
// Add a handler for the asynchrone process and download the file(s)
// in the group “Help”
oDeploy.DownloadFileGroupCompleted += new
DownloadFileGroupCompletedEventHandler(
oDeploy_DownloadFileGroupCompleted);
oDeploy.DownloadFileGroupAsync("Help");
}
}
void oDeploy_DownloadFileGroupCompleted(object sender,
DownloadFileGroupCompletedEventArgs e){
// If the Group is Help display the content of the file.
if(e.Group.Equals("Help")){
MessageBox.Show(File.ReadAllText("ClickHelp.txt"));
}
}
[/code] 

References
  • OReilly Use ClickOnce to Deploy Windows Applications (2006).chm

Create and Deploy .NET Core WebApp to Azure from Linux

(Ce billet en aussi disponible en français.)

The other day, I was glued to my PC, and I had spare time (yah, I know very unusual). Since .Net Core 1.0 was just released few days before, I decide to give it a try. To add an extra layer of fun in the mix, I decided to do it from my Ubuntu VM. In less than 15 minutes, everything was done! I was so impressed I knew I needed to talk about it. That's exactly what this post is about.

The preparation

Before we get started, it's important to know which version of Ubuntu you are using, because some commands will be slightly different. To know the version you are running you simply need to click the gear in the top right of the desktop screen and select About this Computer. In my case, since I'm using Ubuntu 14.04 LTS, I will be using command related to this version. If you are using a different version, please refer to .NET Core documentation.

ubuntu_version

Now we need to install .Net Core. Nothing more easy. Open a Terminal (Ctrl+Alt+T) and type those three commands:

# Setup the apt-get feed adding dotnet as repo
sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet/ trusty main" > /etc/apt/sources.list.d/dotnetdev.list'
apt-key adv --keyserver apt-mo.trafficmanager.net --recv-keys 417A0893

# Get the latest packages
apt-get update

# Install .NET Core SDK
sudo apt-get install dotnet-dev-1.0.0-preview2-003121
Once it's all done you can type dotnet --info and you should see something like that.

dotnet_info


Create the Local WebApp

From the same Terminal we will create an empty folder for our solution and move into it. Execute these commands.
mkdir demodotnetweb
cd demodotnetweb
We now want to create our new web project. This is done by the command dotnet new, but we need to specify the type otherwise it will create a console application.
dotnet new -t web
Now to download all the references (nuget packages) of our project required, execute the following command:
dotnet restore
Base on the speed of your Internet connection and how many dependencies are required, this can take from few seconds to more than one minute.
To test if our solution works locally type the command:
dotnet run
That will compile our solution and start an AspNetCore Internal hosting. Launch a web browser and go to http://localhost:5000 to see the App in action.

dotnetcore_localhost

Deploy to Azure

To deploy our new project to the cloud, we will use the continuous deployment capability of Azure. First, navigate to portal.azure.com and create a Web App.

create_webApp

Once the the application is created, you should see the This web app as been created message when you navigate to the [nameofWebApp].azurewebsites.net

successfully_created

It's now time to add a local Git repository. In the WebApp Settings select Deployment source. Click on the Configure Required Settings, then select the Local Git Repository option.

add_source_control

After setting the user credential for the repository, we can get the URL from the Essential section.

repourl

Back to our Ubuntu Terminal, we will have to execute these commands:

# create a git repository
git init
# commit all files
git commit -m "Init"

# Add the remote repository
git remote add azure https://username@demowebcore.scm.azurewebsites.net:443/demowebcore.git

# Push the code to the remote
git push azure master
After a minute or so you should have your WebApp online!

dotnetcore_azure


Voila! That was fun!.

How to Unzip Automatically your Files with Azure Function v2

I published a video that explains how to UnZip files without any code by using Logic Apps. However, that solution didn't work for bigger files or different archive type. This post is to explain how you can use the Azure Function to cover those situations. This first iteration supports "Zip" files; all the code is available in my GitHub.

Prerequisites


To create the Azure Function, I will use the excellent Azure Function extension of Visual Studio Code. You don't "need" it. However, it makes thing very easy.


You can easily install the extension from Inside Visual Studio Code by clicking on the extension button in the left menu. You will also need to install the Azure Function Core Tools

Creating the Function


Once the extension installed, you will find a new button in the left menu. That opens a new section with four new option: Create New Project, Create Function, Deploy to Function App, and Refresh.


Click on the first option Create New Project. Select a local folder and a language; for this demo, I will use C#. This will create a few files and folder. Now let's create our Function. From the extension menu, select the second option Create Function. Create a Blob Trigger named UnzipThis into the folder we just created, and select (or create) Resource Group, Storage Account, and location in your subscription. After a few seconds, another question will pop asking the name of the container that our blob trigger monitors. For this demo, input-files is used.

Once the function is created you will see this warning message.


What that means is that to be able to debug locally we will need to set the setting AzureWebJobsStorage to UseDevelopmentStorage=true in the local.settings.json file. It will look like this.

{
    "IsEncrypted": false,
    "Values": {
        "AzureWebJobsStorage": "UseDevelopmentStorage=true",
        "FUNCTIONS_WORKER_RUNTIME": "dotnet",
        "unziptools_STORAGE": "DefaultEndpointsProtocol=https;AccountName=unziptools;AccountKey=XXXXXXXXX;EndpointSuffix=core.windows.net",
    }
}

Open the file UnzipThis.cs; this is our function. On the first line of the function, you can see that the Blob trigger is defined.

[BlobTrigger("input-files/{name}", Connection = "cloud5mins_storage")]Stream myBlob

The binding is attached to the container named input-files, from the storage account reachable by the connection "cloud5mins_storage". The real connectionString is in the local.settings.json file.

Now, let's put the code we need for our demo:

[FunctionName("Unzipthis")]
public static async Task Run([BlobTrigger("input-files/{name}", Connection = "cloud5mins_storage")]CloudBlockBlob myBlob, string name, ILogger log)
{
    log.LogInformation($"C# Blob trigger function Processed blob\n Name:{name}");

    string destinationStorage = Environment.GetEnvironmentVariable("destinationStorage");
    string destinationContainer = Environment.GetEnvironmentVariable("destinationContainer");

    try{
        if(name.Split('.').Last().ToLower() == "zip"){

            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(destinationStorage);
            CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
            CloudBlobContainer container = blobClient.GetContainerReference(destinationContainer);
            
            using(MemoryStream blobMemStream = new MemoryStream()){

                await myBlob.DownloadToStreamAsync(blobMemStream);

                using(ZipArchive archive = new ZipArchive(blobMemStream))
                {
                    foreach (ZipArchiveEntry entry in archive.Entries)
                    {
                        log.LogInformation($"Now processing {entry.FullName}");

                        //Replace all NO digits, letters, or "-" by a "-" Azure storage is specific on valid characters
                        string valideName = Regex.Replace(entry.Name,@"[^a-zA-Z0-9\-]","-").ToLower();

                        CloudBlockBlob blockBlob = container.GetBlockBlobReference(valideName);
                        using (var fileStream = entry.Open())
                        {
                            await blockBlob.UploadFromStreamAsync(fileStream);
                        }
                    }
                }
            }
        }
    }
    catch(Exception ex){
        log.LogInformation($"Error! Something went wrong: {ex.Message}");

    }            
}

UPDATED: Thanks to Stefano Tedeschi who found a bug and suggested a fix.

The source of our compressed file is defined in the trigger. To define the destination destinationStorage and destinationContainer are used. Their value are saved into local.settings.json. Then because this function only supports .zip file a little validation was required.

Next, we create an archive instance using the new System.IO.Compression library. We then create references to the storage account, blob, and container. It not possible to used second binding here because for one archive file you have a variable number of potential extracted files. The bindings are static; therefore we need to use the regular storage API.

Then for every file (aka entry) in the archive the code upload it to the destination storage.

Deploying


To deploy the function, from the Azure Function extension click on the third option: Deploy to Function App. Select your subscription and Function App name.

Now we need to configure our settings in Azure. By default, the local.setting are NOT used. Once again the extension is handy.


Under the subscription expand the freshly deployed Function App AzUnzipEverything, and right-click on Application Settings. Use Add New Setting to create cloud5mins_storage, destinationStorage and destinationContainer.

The function is now deployed and the settings are set, now we only need to create the blob storage containers, and we will be able to test the function. You can easily do that directly from the Azure portal (portal.azure.com).

You are now ready to upload a file into the input-files container.

Let's Code Together


This first iteration only supports "Zip" files. All the code is available on GitHub. Feel free to use it. If you would like to see or add support for other archive types join me on GitHub!.

In a video, please!


I also have a video of this post if you prefer.



I also have an extended version where I introduce more the Visual Studio Extension to work with Azure Function. And explain more details about the Azure Function V2.

How to be efficient with our Azure Devtest Lab deployments

(Ce billet est en aussi disponible en français.)

The Devtest labs is a fantastic tool to quickly build environments for development & test purposes and for a classroom. It offers great tools to restrict the users without removing all their freedom. It will speed up the boarding, with its claimable VMs that are already created and are waiting for the user. Formulas will help ensure you that you always get the latest version of your artifact installed on those VMs. And finally, the auto-shutdown will keep your money where it should stay...in your pocket.


In this post, I will show you how to deploy an Azure Devtest Lab with an Azure Resource Manager (ARM) template, and create the claimable VMs based on your formulas in one shot.

Step 1 - The ARM template


First, we need an ARM template. You can start from scratch of course, but it may be a lot of work if you are just getting started. You can also pick one from GiHub and customize it.

What I recommended, is to create a simple Azure Devtest Lab directly from the Azure portal. Once your lab is created, go in the Automation script option of the resourcegroup and copy/paste the ARM template in your favorite text editor.
armTemplate
Now you must clean it. If you don't already know it, use the 5 Simple Steps to Get a Clean ARM Template method, it an excellent way to get started.
Once the template is clean we need to add a few things that didn't follow during the export. Usually, in an ARM template, you get one list named resources. However, a Devtest Lab also contains a list named resources but it's probably missing.
{
    "parameters": {},
    "variables": {},
    "resources": [],
}
See In the following example, I added the labs resources list just after the lab's location. This list must contain a virtualnetworks. It's also a good idea to add a schedules and a notificationChannels. Those two will be used to shut down automatically all the VMs and to send a notification to the user just before.

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        ...
    },
    "variables": {
        ...
    },
    "resources": [
        {
            "type": "Microsoft.DevTestLab/labs",
            "name": "[variables('LabName')]",
            "apiVersion": "2016-05-15",
            "location": "[resourceGroup().location]",
            "resources": [
                {
                    "apiVersion": "2017-04-26-preview",
                    "name": "[variables('virtualNetworksName')]",
                    "type": "virtualnetworks",
                    "dependsOn": [
                        "[resourceId('microsoft.devtestlab/labs', variables('LabName'))]"
                    ]
                },
                {
                    "apiVersion": "2017-04-26-preview",
                    "name": "LabVmsShutdown",
                    "type": "schedules",
                    "dependsOn": [
                        "[resourceId('Microsoft.DevTestLab/labs', variables('LabName'))]"
                    ],
                    "properties": {
                        "status": "Enabled",
                        "timeZoneId": "Eastern Standard Time",
                        "dailyRecurrence": {
                            "time": "[variables('ShutdowTime')]"
                        },
                        "taskType": "LabVmsShutdownTask",
                        "notificationSettings": {
                            "status": "Enabled",
                            "timeInMinutes": 30
                        }
                    }
                },
                {
                    "apiVersion": "2017-04-26-preview",
                    "name": "AutoShutdown",
                    "type": "notificationChannels",
                    "properties": {
                        "description": "This option will send notifications to the specified webhook URL before auto-shutdown of virtual machines occurs.",
                        "events": [
                            {
                                "eventName": "Autoshutdown"
                            }
                        ],
                        "emailRecipient": "[variables('emailRecipient')]"
                    },
                    "dependsOn": [
                        "[resourceId('Microsoft.DevTestLab/labs', variables('LabName'))]"
                    ]
                }
            ],
            "dependsOn": []
        }
        ...

Step 2 - The Formulas


Now that the Devtest lab is well defined, it's time to add our formulas. If you had created some already from the portal, don't look for them in the template. At the moment, export won't script the formulas.

A quick way to get the JSON of your formulas is to create them from the portal and then use Azure Resources Explorer to get the code.
resourceExplorer
In a web browser, navigate to https://resources.azure.com, to open your Resource Explorer. Select the subscription, resource group, and lab that you are working on. In the node Formulas (4) you should see your formulas, click one and let's bring that JSON into our ARM template. Copy-paste it at the Resource level (the prime one, not the one inside the Lab).

Step 2.5 - The Azure KeyVault


You shouldn't put any password inside your ARM template, however, having them pre-define inside the formulas is pretty convenient. One solution is to use an Azure KeyVault.

Let's assume the KeyVault already exists, I will explain how to create it later. In your parameter file, add a parameter named adminPassword and let's reference the KeyVault. We also need to specify the secret we want to use. In this case, we will put the password in a secret named vmPassword.
    "adminPassword": {
        "reference": {
            "keyVault": {
                "id": "/subscriptions/{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}/resourceGroups/cloud5mins/providers/Microsoft.KeyVault/vaults/Cloud5minsVault"
            },
            "secretName": "vmPassword"
        }
    }
Now to get the password in the ARM template just use a regular parameter, and voila!

Step 3 - The ARM Claimable VMs


Now we have a Lab and the formulas, the only thing missing is the claimable VM based on the formulas. It's impossible to create in one ARM template both formulas and VMs. The alternative is to use a script that will create our VMs just after the deployment.
az group deployment create --name test-1 --resource-group cloud5mins --template-file DevTest.json --parameters DevTest.parameters.json --verbose

az lab vm create --lab-name C5M-DevTestLab -g  cloud5mins --name FrankDevBox --formula SimpleDevBox  
As you can see in the second Azure CLI command, we are creating a virtual machine named FrankDevBox based on the formula SimpleDevBox. Note that we don't need to specify any credential because everything was pre-defined in the formula. Pretty neat!

Here a part of a script that will create if it doesn't exist a KeyVault and populate it. Then it will deploy our ARM template and finally, create our claimable VM. You can find all the code on my GitHub project: Azure-Devtest-Lab-efficient-deployment-sample.

[...]

# Checking for a KeyVault
searchKeyVault=$(az keyvault list -g $resourceGroupName --query "[?name=='$keyvaultName'].name" -o tsv )
lenResult=${#searchKeyVault}

if [ ! $lenResult -gt 0 ] ;then
    echo "---> Creating keyvault: " $keyvaultName
    az keyvault create --name $keyvaultName --resource-group $resourceGroupName --location $resourceGroupLocation --enabled-for-template-deployment true
else
    echo "---> The Keyvaul $keyvaultName already exists"
fi


echo "---> Populating KeyVault..."
az keyvault secret set --vault-name $keyvaultName --name 'vmPassword' --value 'cr@zySheep42!'


# Deploy the DevTest Lab

echo "---> Deploying..."
az group deployment create --name $deploymentName --resource-group $resourceGroupName --template-file $templateFilePath --parameters $parameterFilePath --verbose

# Create the VMs using the formula created in the deployment

labName=$(az resource list -g cloud5mins --resource-type "Microsoft.DevTestLab/labs" --query [*].[name] --output tsv)
formulaName=$(az lab formula list -g $resourceGroupName  --lab-name $labName --query [*].[name] --output tsv)

echo "---> Creating VM(s)..."
az lab vm create --lab-name $labName -g  $resourceGroupName --name FrankSDevBox --formula $formulaName 
echo "---> done <--- code="">

In a video, please!


I also have a video of this post if you prefer.



Conclusion


Would it be for developing, testing, or training, as soon as you are creating environments in Azure, the DevTest Labs are definitely a must. It's a very powerful tool that not enough people know. Give it a try and let me know what do you do with the Azure DevTest Lab?


References:

  • Azure-Devtest-Lab-efficient-deployment-sample: https://github.com/FBoucher/Azure-Devtest-Lab-efficient-deployment-sample
  • An Overview of Azure DevTest Labs: https://www.youtube.com/watch?v=caO7AzOUxhQ
  • Best practices Using Azure Resource Manager (ARM) Templates: https://www.youtube.com/watch?v=myYTGsONrn0&t=7s
  • 5 Simple Steps to Get a Clean ARM Template: http://www.frankysnotes.com/2018/05/5-simple-steps-to-get-clean-arm-template.html



~

6 ways to go from Markdown to Azure Web App

Everything started when I wanted to share a blog post in progress to someone for review. I didn't want to create a copy, and I was looking for an extremely simple way to share; like an url. This blog post is about all my journey to find that method and all the great possibilities available. I was really happy to that Azure Web App.
I'm writing in Markdown, it's a syntax I really like because it's simple no special application is required to use it. To know more about it see my previous post: Why I switch to Markdown, First VSCode Tasks in less than 5 minutes and Meet my new best friend: Visual Studio Code. The more I use it, the more I like it. I started using it not only not only for blogging, but also for all kinds of notes.

DropBox

One very good thing about Markdown is the fact that is compatible with all platforms. Because of that, I keep my texts in Dropbox. Why not Google Drive or OneDrive? Because Dropbox automatically generates the HTML version so my reviewer could read it in a beautiful format. The file is share-able very easily and if authenticated my reviewer could write comment.
dropboxpostsharing
In the PRO version, of DropBox, you can give access only to specific user. That would be very nice for sharing files inside a business or more sensible information.
Unfortunately for me, I don't want to force my reviewer to register. Another interesting fact is that relative paths for images aren't supported. So all images/ charts need also to be share individually before added in the text.

Repositories: GitHub, Bitbucket, etc.

By default, most repositories convert markdown file to HTML so very easy to read. It's also a very good way to have a saved copy. But then you need to have a public repository or give access to people...
Only using repository was not good enough in my case because I don't wish to share unfinished work with everyone.

Jekyll


Option 1 - Jekyll

Jekyll is a static website generator written in Ruby. It's really well integrated to Github, and you can even host your blog in a Github repository. However, since I would prefer to keep my in progress work more private, I decided to go with Bitbucket. Bitbucket is a great repository that supports Git and Mercurial system and allowed private repositories.
We could have Jekyll in a Git repository host on Bitbucket that would be hook-up to an Azure Web App with a continuous deployment.
Here the steps:
  1. First create a private repository from Bitbucket.
  2. Clone that fresh repository on your local machine.
  3. Now it's time to create your Jekyll site.
    • If you don't have Ruby or Jekyll already installed on your machine now it's time. It's very easy just follow the instruction on the official website.
    • To create a new site, open a command prompt and type the command: jekyll new NameOfMySite then cd ./NameOfMySite and jekyll serve
    To see your new site you just need to browse to http:localhost:4000. Add your Markdown files to the folder _posts and be sure they respect the naming convention YYYY-MM-DD-Title.md
  4. Now it's time to add all the files to our Git repository with the command git add -A, and before pushing let create a new Azure Web App.
  5. Go to http://portal.azure.com a create a new Azure Web App.
    CreateAzureWebApp
    • From the top left click the "+ New" button.
    • Select Web+ Mobile, then click on Web App
    • Fill-up the name, subscription plan and click the create button.
  6. After few second, the Web App will be ready. It's time to add a continuous deployment to it.
    AddContinuous
    Note: that right now the deployment settings are FTP.
    • In the Web App blade, if not already go in the Setting section.
    • Scroll done the Settings to Continuous deployment and click on it.
    • Now choose your source control, in this case Bitbucket.
  7. It's now time to publish our site to our Remote repository with git push.
  8. In the Azure portal, you will see the deployment progress and history.
    DeploymentHistory
The combination Jekyll / Bitbucket / Azure Web App work great, but we need to generate the code locally and checked-in both source and generated content in the repository. Furthermore, since we need to generate the code, Ruby and Jekyll need to be installed on every machine we will be using.

Option 2 - Jekyll Extension to Azure Web App

I found a really great Azure Web App Extension Jekyll Extenstion on GitHub. That will simplify a lot the process thanks to Cory's works. To use it simple follow the four steps explain on the Github page:

  1. Create an Azure Web App 
  2. Set an App Setting for SCM_COMMAND_IDLE_TIMEOUT to 600. From the Web App blade click on Settings and select Application settings.  Add the new line, and click the save button.
     SCM_AppSetting
  3. Install the Jekyll Site Extension
    • Always From the Web App blade click on Tools, then select Extension
    • Click Add button
    • Found and select Jekyll Extension AddJekyllExtension
  4. Now we need to hook up your Git repository or Push a local (in Azure) Git repository with your Jekyll site.
I really liked this solution. It's very simple to install. Because it used a repository, I can keep a historic of all my texts. Moreover, only the texts and images are in the repository, and since the site is generated in the cloud, no need to install anything on other machines.
WriteFromVSCode
Directly from Visual Studio Code, I can write my article, and when I'm read I just need to do a push (still inside VSCode). The site will automatically be built and deployed in my Azure Web App.

Santra.Snow

NancylogoWhile doing my research, I found Sandra.Snow another static site generator inspired from Jekyll but in .Net using Nancy library.
To use it, a little bit of work is required. The easiest way is to fork the Github project and compile the solution to get dlls and exes.
  • Create a new folder for your site [MySnowSite].
  • In MySnowSite folder, create another folder Sandra.Snow.Processor and copy/paste: Nancy.dll, Nancy.Testing.dll, Nancy.ViewEngines.Razor.dll and Snow.exe generated previously.
  • You can now copy the Sandra.Snow/SnowSite/Snow folder into MySnowSite folder.
  • Add deployment and deploy.cmd files from Sandra.Snow/SnowSite into MySnowSite folder.
SandraSnowFolder
Few changes were required in deploy.cmd (line: 29, 31, 56, 57)
@echo off

:: ----------------------
:: KUDU Deployment Script
:: ----------------------

:: Setup
:: -----

setlocal enabledelayedexpansion

SET ARTIFACTS=%~dp0%artifacts

IF NOT DEFINED DEPLOYMENT_SOURCE (
  SET DEPLOYMENT_SOURCE=%~dp0%.
)

IF NOT DEFINED DEPLOYMENT_TARGET (
  SET DEPLOYMENT_TARGET=%ARTIFACTS%\wwwroot
)

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Deployment
:: ----------

:: 3. Build Snow Site
echo -----
echo Start - Building the Snow Site
echo Running Snow.exe config=%DEPLOYMENT_SOURCE%\Snow\
pushd %DEPLOYMENT_SOURCE%
call  %DEPLOYMENT_SOURCE%\Sandra.Snow.Processor\Snow.exe config=%DEPLOYMENT_SOURCE%\Snow\
IF !ERRORLEVEL! NEQ 0 goto error
echo Finish - Building the Snow Site
echo -----


IF NOT DEFINED NEXT_MANIFEST_PATH (
  SET NEXT_MANIFEST_PATH=%ARTIFACTS%\manifest

  IF NOT DEFINED PREVIOUS_MANIFEST_PATH (
SET PREVIOUS_MANIFEST_PATH=%ARTIFACTS%\manifest
  )
)

IF NOT DEFINED KUDU_SYNC_COMMAND (
  :: Install kudu sync
  echo Installing Kudu Sync
  call npm install kudusync -g --silent
  IF !ERRORLEVEL! NEQ 0 goto error

  :: Locally just running "kuduSync" would also work
  SET KUDU_SYNC_COMMAND=node "%appdata%\npm\node_modules\kuduSync\bin\kuduSync"
)


echo Kudu Sync from "%DEPLOYMENT_SOURCE%\Snow\Website" to "%DEPLOYMENT_TARGET%"
call %KUDU_SYNC_COMMAND% -q -f "%DEPLOYMENT_SOURCE%\Snow\Website" -t "%DEPLOYMENT_TARGET%" -n "%NEXT_MANIFEST_PATH%" -p "%PREVIOUS_MANIFEST_PATH%" -i ".git;.deployment;deploy.cmd" 2>nul
IF !ERRORLEVEL! NEQ 0 goto error

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

goto end

:error
echo An error has occured during web site deployment.
exit /b 1

:end
echo Finished successfully.
Like previously created a Azure Web App and hook up a Git repository or push to an Azure one. You can find a lot of information on the blog of Sandra.Snow creator Phillip Haydon.

Bonus

For both Jekyll (option 2) and Sandra.Snow that used Azure Web App continuous deployment use can use Dropbox instead of Git repository. Why would you use Dropbox? Well, since Dropbox is available on any kind of platform, you would be able to write from your iPad or android tablet, or anything! To learn more about how to do it, see one of my previous post: Setup an automatic deployment on Azure with Dropbox in 5 minutes.
Just for the fun, I created one theme for Sandra.Snow that I put on GitHub: Sandra.Snow.NotesTheme, feel free to use it.

Enjoy!

~Frank Boucher

Reading Notes #574


It is time to share new reading notes. It is a habit I started a long time ago where I share a list of all the articles, blog posts, and books that catch my interest during the week.

If you think you may have interesting content, share it!

Cloud

Programming

Podcasts

  • Going Full Time on Open Source with Shaun Walker (.NET Rocks!) - The older will remember the amazing DotNetNuke. That OSS project was create by Shaun a few years ago. In this episode, they talk about his new project and how he is building it.

Miscellaneous

~frank