in relation to my other question on how to set the document root for a Azure Web Site, I would like to know how to do the same with a Cloud Service.
I've used the Azure Powershell Tools to create a package of my application and succesfully uploaded it to the cloud. But setting document root is not working.
My ServiceDefinition.csdef looks like this:
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="myCloudService" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
<WebRole name="myWebRole" vmsize="ExtraSmall">
<Imports />
<Startup>
<Task commandLine="setup_web.cmd > log.txt" executionContext="elevated">
<Environment>
<Variable name="EMULATED">
<RoleInstanceValue xpath="/RoleEnvironment/Deployment/@emulated" />
</Variable>
<Variable name="RUNTIMEVERSIONPRIMARYKEY" value="5.3.17" />
<Variable name="RUNTIMEID" value="PHP" />
<Variable name="RUNTIMEURL" value="http://az413943.vo.msecnd.net/php/5.3.17.exe" />
</Environment>
</Task>
</Startup>
<Endpoints>
<InputEndpoint name="Endpoint1" protocol="http" port="80" />
</Endpoints>
<Sites>
<Site name="Web">
<Bindings>
<Binding name="Endpoint1" endpointName="Endpoint1" />
</Bindings>
</Site>
</Sites>
</WebRole>
</ServiceDefinition>
Now I've tried setting the physicalDirectoryPath for the site directly
<Sites>
<Site name="Web" physicalDirectory="../htdocs">
...
</Site>
</Sites>
and I've tried to use a VirtualApplication, but both don't seem to work.
<Sites>
<Site name="Web">
<VirtualApplication name="MyWeb" physicalDirectory="../htdocs" />
...
</Site>
</Sites>
Any help?
Following a Blog entry, I found a solution that works. I'll sum it up to give a quick insight on how to do it:
Link: Change your azure websites root folder
You have to add da startup task in your ServiceDefinition.csdef file
<Startup>
<Task commandLine="changeroot.cmd" executionContext="elevated" taskType="background" />
</Startup>
This instructs each instance on startup to execute 'changeroot.cmd'. This file hast to go into the /bin directory of your web role instance directory.
This contains the following code:
@echo off
cd "%~dp0"
icacls %RoleRoot%\approot /grant "Everyone":F /T
powershell.exe Set-ExecutionPolicy Unrestricted
powershell.exe .\changeroot.ps1
ECHO Changeroot Run. >> ..\startup-tasks-log.txt
This will execute the powershell changeroot.ps1 script, with elevated user right, that will move the physicalPath of the site in IIS once it is created. This also has to go into your /bin path in your web role.
It contains the following code:
$siteName = "Web"
$serverIP = "127.0.0.1"
$newPath = "htdocs" ## your document root
$pathset = $false
$trycount = 0
##loop until physical path has changed
while($pathset -eq $false) {
$trycount += 1
##if the role id can be determined
if([Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment]::CurrentRoleInstance.Id -ne $null)
{
$fullName = [Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment]::CurrentRoleInstance.Id + "_" + $siteName
$op = "Changeroot: Site Full Name: $fullName`r`n"
Write-Output $op | Out-File -Encoding Ascii ..\startup-tasks-log.txt
##init server manager
$serverManager = [Microsoft.Web.Administration.ServerManager]::OpenRemote($serverIP)
if($serverManager -ne $null)
{
$op = "Changeroot: Site Manager Setup`r`n"
Write-Output $op | Out-File -Encoding Ascii ..\startup-tasks-log.txt
##load site
$site = $serverManager.Sites | where { $_.Name -eq $fullName }
if($site -ne $null)
{
$op = "Changeroot: Site loaded ($fullName)`r`n"
Write-Output $op | Out-File -Encoding Ascii ..\startup-tasks-log.txt
##change physical path
$rootApp = $site.Applications | where { $_.Path -eq "/" }
$rootVdir = $rootApp.VirtualDirectories | where { $_.Path -eq "/" }
$dir = $rootVdir.PhysicalPath.EndsWith('\')
if($dir -eq $true) {
$rootVdir.PhysicalPath += $newPath + "\"
} else {
$rootVdir.PhysicalPath += "\" + $newPath + "\"
}
$serverManager.CommitChanges()
$op = "Root changed for $fullName (after $trycount tries)`r`n"
Write-Output $op | Out-File -Encoding Ascii ..\startup-tasks-log.txt
$pathset = $true
exit
}
}
} else {
startup-tasks-log.txt
}
# Restart the loop in 5 seconds
Start-Sleep -Seconds 5
}
This finally worked for me.
For a more detailed explanation please follow the link.
An added precaution:
Make sure you build your package (or deploy using publish-azureserviceproject
) using a build machine that has a matching (or lesser) .net framework as your cloud host. If deploying on a Windows 8.1 machine, you may need to make sure your OSFamily is set to 4. In order to verify that your .net runtimes aren't newer on your build machine than they are on your cloud host:
- open a powershell on both machines
- take a look at
[System.Environment]::Version
or if you're using powershell 2.0 or newer, you can look at the $PSVersionTable
variable
The problems you'll run into if you don't do this - you likely won't be able to use any of the Azure Assemblies such as Microsoft.WindowsAzure.ServiceRuntime. Changing the Physical Path of a web site depends on knowing the web site name and this is only (dynamically) available in that assembly.