Deploying a Website with Content through Visual Studio with Resource Groups


UPDATED: This post has been updated to reflect the recent changes.

If you are like me you were glued to the computer watching all of the Build and Ignite sessions, what an exciting couple weeks.  One of the great things that came out was the Azure SDK 2.6 for .NET.  With this we got..

  • Azure Resource Manager Tools
  • Diagnostics improvements for Cloud Services
  • Azure App Service Tools
  • HDInsight tools

I am going to focus on Resource Manager Tools.  If you have not played with Azure Resource Manager (ARM) you are missing out, it has some great features over the existing Service Management tools.  One of these is being able to deploy resource groups, now you may be saying well Resource Groups have been around for a while.  While that is the case there is a lot of great new things that were announced.  The new v2 versions of VMs, Storage Accounts, Network adapters.. these are all amazing things.

In this blog though I am going to take you through deploying a full functional website leveraging Resource Groups, Visual Studio and WebDeploy.

Before starting visit the download site https://azure.microsoft.com/en-us/downloads/ to download the SDK for your version of Visual Studio.

Create your web content

For the sake of the blog I will step you through creating example content for your site, for this you will need to launch Visual Studio, Create a new ASP.NET Web Application.

image

For this example lets choose Web API which should be the default and click OK. While you may be tempted to click Host in the cloud, leave that unchecked for now.  Visual Studio does a great job of deploying websites to Azure and adding Application Insights, but we are going to do it differently.

image

Now lets right click the Project name and click Publish, for the publish target click Custom and give it a name and click Ok

image

For the Publish method we are going to choose a Web Deploy Package, this way we can save the package offline on our system and use that to deploy out our site, choose a Package location and give your site a name, finally click Publish.  Now note where you saved that package as we are going to use it a little later.

image

Create your Resource Group Project

Keeping that existing solution opened we created, create a new Project in the solution by Right Clicking the solution, choose Add then New Project…

image

Choos Visual C#, Cloud and Azure Resource Group, give your project a name and click OK this will create another project in our solution specifically for our Resource Group.

image

Now there is already a template for Web App here, but I am going to take you through creating this from a blank template so you get a better understanding of the capabilities. Find Blank Template and click OK.

image

Expand out the Templates folder and double click DeploymentTemplate.json, and a basically empty json document will open, here it has the major components to a Resource Group Template

  • Parameters – These will be used to pass data into your Resource Group Template Deployment
  • Variables – These help will defining variables that can be used to define values you may reuse
  • Resources – These are the resources that you will be adding to the resource group (NICS, VMs, Websites, etc)
  • Output – This is for defining any output that you may have.

All of these items are shown as well in the left panel in the JSON Outline window.  These will be our graphical representation of our JSON file. Go ahead and click the cube with the plus sign to add a Resource.  For the Website we are going to create we need 4 different items.

  • App Service Plan
  • Application Insights for Web Apps
  • Web App
  • Web Deploy for Web Apps

First Choose the App Service Plan (Server Farm) give it a name and click Add

image

You will see in the outline by adding that Resource we now have 1 Resource and 4 Parameters.. These parameters come with the App Service Plan Template

image

If you click on any of the Parameters it will focus the DeploymentTemplate.json file to the item you clicked. As you notice those parameters have their definitions, all are string values, but the SerferFarmSKU and ServerFarmWorkerSize have defined values they can be.  This is useful to force people when reusing your template to make sure they put in correct values.  For instance the SKU relates to the type of website, in Azure we have Free Shared, Basic and Standard.

image

There is nothing left to do now for the App Service Plan so lets move on to the Web App.  Click the Cube with a plus in the JSON Outline window and choose a Web App this time, give it a name, now you will notice since your file already has a Service Plan it will be automatically selected.  This is great as it will build out your dependencies for you in the JSON Template file.  Once you are done go ahead and click Add

image

So now if we wanted to deploy it now we could and have a basic website.  But remember we created that Web Deploy Package earlier.  Lets get that Web Deploy Package as well.  Click the cube with the plus sign and choose Web Deploy for Web Apps.  Give it a name and just as before the dependencies, in this case a Web App was already selected.  Now just click Add

image

By now if you look in the JSON Outline we have some more items for the Web App and the Web Deploy for Web Apps. Take note that the Web Deploy for Web Apps is nested under the WebApp, it is a child in the hierarchy.

image

Now we need to get that Web Deploy Package we created earlier where it needs to be. First we need to quickly Build what we have so far.  On the Menu click Built and then Build Solution.

image

Once the build is done we will right click the Project and choose Open Folder in File Explorer, when the folder opens navigate to bin\Debug\Artifacts\<Project Name>

image

Navigate to where you saved your Web Deploy Package and paste it in this folder. This file needs to be in the folder as when you deploy the deployment script will look in this folder for any artifacts and can deploy them to a storage account to be referenced later by the script later.

image

Now we will go ahead and add Application Insights to the Web App, again click the cube with the plus signs, this time choose Application Insights for Web Apps.  Give it a Name and as noted before since we only have one App Service Plan and one Web App they are already preselected. Then click Add to add it to our resource group

image

For the sake of this blog post we wont modify the JSON but as you can see it added a few predefined settings for AppInsights, CPU, Queues, Server Errors, etc to be monitored.

image

Now we are just about ready to deploy. In the Solution Explorer, right click your project, choose deploy and New Deployment…

image

When the window pops up if not already signed in click the Sign In button

image

Once you are signed in, choose your subscription, you could add this to an existing Resource Group but we will add it to a new one for the sake of the blog post.  Pull down the drop down on Resource Group and choose <Create New…>

image

Give the Resource Group a name and choose a location, we will use this location later as well.

image

Choose a Storage account for your Artifacts, in this case our Web Deploy package, this can not be created on the fly it must be an existing one in your subscription.  When you are ready click Deploy.

image

When you click deploy you will get an Edit Parameters window.  In here we need to fill in the parameters.  These could be updated in your azuredeploy.parameters.json file, but since we just have a few options we will fill it out by hand.  As you can see the SKU and Worker Size we saw earlier are drop down boxes, that is because we allowed it to have a few different values.  Since we put our Web Deploy package in the main folder, put in your Project name, this folder will be created by default, if you were to make a sub folder you could enter it as <ProjectName>\<Myfolder>. Fill out the fields and click Save

image

When you are done you will see output similar to below.

20:39:02 - Build started.
20:39:02 – Project "MyAwesomeWebsiteResourceGroup.deployproj" (StageArtifacts target(s)):
20:39:02 - Project "MyAwesomeWebsiteResourceGroup.deployproj" (ContentFilesProjectOutputGroup target(s)):
20:39:02 - Done building project "MyAwesomeWebsiteResourceGroup.deployproj".
20:39:02 - Done building project "MyAwesomeWebsiteResourceGroup.deployproj".
20:39:02 - Build succeeded.
20:39:02 - The following parameter values will be used for this deployment:
20:39:02 -     MyAwesomeWebsiteServerFarmName: MyAwesomeWebsite
20:39:02 -     MyAwesomeWebsiteServerFarmSKU: Free
20:39:02 -     MyAwesomeWebsiteServerFarmWorkerSize: 0
20:39:02 -     _artifactsLocation:
20:39:02 -     _artifactsLocationSasToken: <securestring>
20:39:02 -     MyAwesomeWebsiteWebDeployPackageFolder: MyAwesomeWebsiteResourceGroup
20:39:02 -     MyAwesomeWebsiteWebDeployPackageFileName: MyAwesomeWebSite.zip
20:39:02 - Launching deployment PowerShell script with the following command:
20:39:02 - 'c:\users\username\documents\visual studio 2015\projects\myawesomewebsiteresourcegroup\myawesomewebsiteresourcegroup\Scripts\Deploy-AzureResourceGroup.ps1' -StorageAccountName 'azril302gvbf' -ResourceGroupName 'azril302nbv' -ResourceGroupLocation 'eastus' -TemplateFile 'c:\users\username\documents\visual studio 2015\projects\myawesomewebsiteresourcegroup\myawesomewebsiteresourcegroup\templates\azuredeploy.json' -TemplateParametersFile 'c:\users\username\documents\visual studio 2015\projects\myawesomewebsiteresourcegroup\myawesomewebsiteresourcegroup\templates\azuredeploy.parameters.json' -ArtifactStagingDirectory '..\bin\Debug\staging' -UploadArtifacts -StorageAccountResourceGroupName 'azril302nbv'
20:39:09 -
20:39:09 -
20:39:09 - Environment           : AzureCloud
20:39:09 - Account               :
username@live.com
20:39:09 - TenantId              : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
20:39:09 - SubscriptionId        : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
20:39:09 - CurrentStorageAccount :
20:39:09 -
20:39:54 -
20:39:54 - Transfer summary:
20:39:54 - -----------------
20:39:54 - Total files transferred: 10
20:39:54 - Transfer successfully:   10
20:39:54 - Transfer failed:         0
20:39:54 - Elapsed time:            00.00:00:41
20:39:54 -
https://azril302gvbf.blob.core.windows.net/azril302nbv-stageartifacts
20:39:55 - [VERBOSE] 8:39:55 PM - Created resource group 'azril302nbv' in location 'eastus'
20:39:56 -
20:39:56 - ResourceGroupName : azril302nbv
20:39:56 - Location          : eastus
20:39:56 - Resources         : {bob0, bob2, CPUHigh MyAwesomeWebsite, CPUHigh
20:39:56 -                     qq2w43141245125...}
20:39:56 - ResourcesTable    :
20:39:56 -                     Name                                           Type       
20:39:56 -                                                  Location     
20:39:56 -                     ============================================= 
20:39:56 -                     =======================================  ==============
20:39:56 -                     bob0                                          
20:39:56 -                     Microsoft.Compute/virtualMachines        eastus       
20:39:56 -                     bob2                                          
20:39:56 -                     Microsoft.Compute/virtualMachines        eastus       
20:39:56 -                     CPUHigh MyAwesomeWebsite                      
20:39:56 -                     Microsoft.Insights/alertrules            eastus       
20:39:56 -                     CPUHigh qq2w43141245125                       
20:39:56 -                     microsoft.insights/alertrules            eastus       
20:39:56 -                     ForbiddenRequests georgenugettestdave         
20:39:56 -                     microsoft.insights/alertrules            eastus       
20:39:56 -                     ForbiddenRequests MyAwesomeWebSiteAppInsights 
20:39:56 -                     Microsoft.Insights/alertrules            eastus       
20:39:56 -                     LongHttpQueue MyAwesomeWebsite                
20:39:56 -                     Microsoft.Insights/alertrules            eastus       
20:39:56 -                     LongHttpQueue qq2w43141245125                 
20:39:56 -                     microsoft.insights/alertrules            eastus       
20:39:56 -                     ServerErrors georgenugettestdave              
20:39:56 -                     microsoft.insights/alertrules            eastus       
20:39:56 -                     ServerErrors MyAwesomeWebSiteAppInsights      
20:39:56 -                     Microsoft.Insights/alertrules            eastus       
20:39:56 -                     MyAwesomeWebsite-azril302nbv                  
20:39:56 -                     Microsoft.Insights/autoscalesettings     eastus       
20:39:56 -                     qq2w43141245125-azril302nbv                   
20:39:56 -                     microsoft.insights/autoscalesettings     eastus       
20:39:56 -                     georgenugettestdave                           
20:39:56 -                     microsoft.insights/components            centralus    
20:39:56 -                     MyAwesomeWebSiteAppInsights                   
20:39:56 -                     Microsoft.Insights/components            centralus    
20:39:56 -                     nic0                                          
20:39:56 -                     Microsoft.Network/networkInterfaces      eastus       
20:39:56 -                     nic2                                          
20:39:56 -                     Microsoft.Network/networkInterfaces      eastus       
20:39:56 -                     asdasd                                        
20:39:56 -                     Microsoft.Network/networkSecurityGroups  northcentralus
20:39:56 -                     publicIP0                                     
20:39:56 -                     Microsoft.Network/publicIPAddresses      eastus       
20:39:56 -                     publicIP2                                     
20:39:56 -                     Microsoft.Network/publicIPAddresses      eastus       
20:39:56 -                     1qa2sanetwork                                 
20:39:56 -                     Microsoft.Network/virtualNetworks        eastus       
20:39:56 -                     azril302gvbf                                  
20:39:56 -                     Microsoft.Storage/storageAccounts        eastus       
20:39:56 -                     MyAwesomeWebsite                              
20:39:56 -                     Microsoft.Web/serverFarms                eastus       
20:39:56 -                     qq2w43141245125                               
20:39:56 -                     Microsoft.Web/serverFarms                eastus       
20:39:56 -                     georgenugettestdave                           
20:39:56 -                     Microsoft.Web/sites                      eastus       
20:39:56 -                     MyAwesomeWebsitepjeak2lppue2k                 
20:39:56 -                     Microsoft.Web/sites                      eastus       
20:39:56 -                    
20:39:56 - ProvisioningState : Succeeded
20:39:56 - Tags              : {}
20:39:56 - TagsTable         :
20:39:56 - ResourceId        : /subscriptions/590d019c-bc64-4ce4-a118-002c35d4086b/resourc
20:39:56 -                     eGroups/azril302nbv
20:39:56 -
20:40:01 - [VERBOSE] 8:40:01 PM - Create template deployment 'azuredeploy-0323-0239'.
20:40:04 - [VERBOSE] 8:40:04 PM - Resource Microsoft.Web/serverfarms 'MyAwesomeWebsite' provisioning status is succeeded
20:40:09 - [VERBOSE] 8:40:09 PM - Resource Microsoft.Insights/alertrules 'CPUHigh MyAwesomeWebsite' provisioning status is succeeded
20:40:09 - [VERBOSE] 8:40:09 PM - Resource Microsoft.Insights/alertrules 'LongHttpQueue MyAwesomeWebsite' provisioning status is succeeded
20:40:09 - [VERBOSE] 8:40:09 PM - Resource Microsoft.Insights/autoscalesettings 'MyAwesomeWebsite-azril302nbv' provisioning status is succeeded
20:40:55 - [VERBOSE] 8:40:55 PM - Resource Microsoft.Web/sites 'MyAwesomeWebsitepjeak2lppue2k' provisioning status is succeeded
20:41:02 - [VERBOSE] 8:41:02 PM - Resource Microsoft.Insights/alertrules 'ForbiddenRequests MyAwesomeWebSiteAppInsights' provisioning status is succeeded
20:41:05 - [VERBOSE] 8:41:05 PM - Resource Microsoft.Insights/alertrules 'ServerErrors MyAwesomeWebSiteAppInsights' provisioning status is succeeded
20:41:05 - [VERBOSE] 8:41:05 PM - Resource Microsoft.Web/sites/extensions 'MyAwesomeWebsitepjeak2lppue2k/MSDeploy' provisioning status is running
20:41:05 - [VERBOSE] 8:41:05 PM - Resource Microsoft.Insights/components 'MyAwesomeWebSiteAppInsights' provisioning status is succeeded
20:41:11 - [VERBOSE] 8:41:11 PM - Resource Microsoft.Web/sites/extensions 'MyAwesomeWebsitepjeak2lppue2k/MSDeploy' provisioning status is succeeded
20:41:15 -
20:41:15 - DeploymentName     : azuredeploy-0323-0239
20:41:15 - CorrelationId      : 9bd2d07e-56b5-4c67-8d05-6849a35f366e
20:41:15 - ResourceGroupName  : azril302nbv
20:41:15 - ProvisioningState  : Succeeded
20:41:15 - Timestamp          : 3/23/2016 2:41:10 AM
20:41:15 - Mode               : Incremental
20:41:15 - TemplateLink       :
20:41:15 - TemplateLinkString :
20:41:15 - Parameters         : {[myAwesomeWebsiteServerFarmName, Microsoft.Azure.Commands
20:41:15 -                      .Resources.Models.DeploymentVariable],
20:41:15 -                      [myAwesomeWebsiteServerFarmSKU, Microsoft.Azure.Commands.R
20:41:15 -                      esources.Models.DeploymentVariable],
20:41:15 -                      [myAwesomeWebsiteServerFarmWorkerSize, Microsoft.Azure.Com
20:41:15 -                      mands.Resources.Models.DeploymentVariable],
20:41:15 -                      [_artifactsLocation, Microsoft.Azure.Commands.Resources.Mo
20:41:15 -                      dels.DeploymentVariable]...}
20:41:15 - ParametersString   :
20:41:15 -                      Name             Type                       Value    
20:41:15 -                      ===============  =========================  ==========
20:41:15 -                      myAwesomeWebsiteServerFarmName  String                   
20:41:15 -                       MyAwesomeWebsite
20:41:15 -                      myAwesomeWebsiteServerFarmSKU  String                    
20:41:15 -                      Free     
20:41:15 -                      myAwesomeWebsiteServerFarmWorkerSize  String             
20:41:15 -                             0        
20:41:15 -                      _artifactsLocation  String                    
https://azr
20:41:15 -                      il302gvbf.blob.core.windows.net/azril302nbv-stageartifacts
20:41:15 -                      _artifactsLocationSasToken  SecureString                 
20:41:15 -                            
20:41:15 -                      myAwesomeWebsiteWebDeployPackageFolder  String           
20:41:15 -                               MyAwesomeWebsiteResourceGroup
20:41:15 -                      myAwesomeWebsiteWebDeployPackageFileName  String         
20:41:15 -                                 MyAwesomeWebSite.zip
20:41:15 -                     
20:41:15 - Outputs            : {}
20:41:15 - OutputsString      :
20:41:15 -
20:41:16 -
20:41:16 -
20:41:16 -
20:41:16 - Successfully deployed template 'c:\users\username\documents\visual studio 2015\projects\myawesomewebsiteresourcegroup\myawesomewebsiteresourcegroup\templates\azuredeploy.json' to resource group 'azril302nbv'.

When it is done give it a few minutes for the web deploy to finish and then navigate to your website… you will see the .net example we deployed is now there.

image

MyAwesomeWebsiteResourceGroup.zip

Comments (10)

  1. Frank says:

    Excellent! I spent ages searching for how to do this! ( By the way, small correction Save your changes and we are NOW ready to deploy )

  2. Vignesh says:

    I am getting below error while following your steps, any help in finding out where I went wrong would be very useful

    15:27:29 - [ERROR] New-AzureRmResourceGroupDeployment : 15:27:29 - Resource
    15:27:29 - [ERROR] Microsoft.Web/sites/extensions 'WebAppui/MSDeploy' failed
    15:27:29 - [ERROR] with message 'The resource operation completed with terminal provisioning

    15:27:29 - [ERROR] state 'Failed'.'
    15:27:29 - [ERROR] At C:projectstreamingoct16azureresourcegroupScriptsDeploy-AzureResourceG
    15:27:29 - [ERROR] roup.ps1:99 char:1
    15:27:29 - [ERROR] + New-AzureRmResourceGroupDeployment -Name ((Get-ChildItem
    15:27:29 - [ERROR] $TemplateFile).BaseName ...
    15:27:29 - [ERROR] + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    15:27:29 - [ERROR] ~~~
    15:27:29 - [ERROR] + CategoryInfo : NotSpecified: (:) [New-AzureRmResourceGroupDeplo

    15:27:29 - [ERROR] yment], Exception
    15:27:29 - [ERROR] + FullyQualifiedErrorId : Microsoft.Azure.Commands.Resources.NewAzureResou

    15:27:29 - [ERROR] rceGroupDeploymentCommand
    15:27:29 - [ERROR]

  3. Jean-Claude Gonnet says:

    Excellent article !

    a href="http://jeanclaudegonnet.hautetfort.com/">Jean-Claude Gonnet

  4. Jakub says:

    I followed the steps from this article (and from others), but deployment always fails. When I check error logs (as described in my previous comment) I see: AppGallery Deploy Failed: 'Microsoft.WindowsAzure.StorageClient.StorageClientException: The value
    for one of the HTTP headers is not in the correct format.

    Has anyone else seen this error? Thanks

  5. I know I need to update the article as the latest SDK changes have changed how it works.. I.e artifacts folder no long exists. That said, it sounds like the uri for your artifact that you are referencing is not correct, can you share what you have foe
    the path?

  6. Jak221 says:

    Thanks for coming back to me George!

    It would be awesome to update the article, but there weren't a many changes to be honest.. it was still easy to follow.

    Anyway, I believe that my paths are correct. I've made some screenshots showing it.

    Here is the error message I see on Kudu:
    http://i.imgur.com/TfNAcjk.png

    Here is the content of my blob (the paths are the same as in the above image):
    http://i.imgur.com/PVeccVY.png

    That's the output of running Deployment from VS:
    http://i.imgur.com/q9C2oIA.png
    (probably not interesting)

    Could you please check if there is some obvious mistake which I am missing? Thanks!

    Thanks a lot for this article btw.. it is surprisingly difficult to find documentation about Azure resource manager.

  7. On the road right now but tonight when I am back at my hotel I will look Inyo your issue and rewrite this post using thr latest SDK. Looking at what you are doing I don't see any issue.

  8. Jak221, Just updated the instructions to map to what is currently in the SDK. Just tested with a new project and the web deploy worked perfectly. Would be curious to see your actual project, without your webdeploy package.. I also don't mind to send mine
    to you if you want to test. The only thing I can think is there is an issue with the packageuri. you click the contect blog author and can send you the info.

Skip to main content