3

我的 Azure Web 角色需要能够删除存储在 App_Data 子文件夹中的临时本地文件。我想在 Azure 提升的启动任务中使用 ICACLS 以允许 IIS 执行此操作,如下所示:

ICACLS App_Data /grant "IIS_IUSRS":(OI)(CI)F

但是,我的启动任务执行于:

E:\approot\bin

而 Web 应用程序实际结束并从中执行的根文件夹似乎是:

E:\sitesroot\0

我不愿意硬编码这条路径,以防微软改变它。有没有办法从启动任务中获取这条路径,或者我可以依赖这个目的地?

为了在 ASPX 中进行测试,我添加了:

Label1.Text = "MapPath: " + Server.MapPath("~/");
Label2.Text = "RoleRoot: " + Environment.GetEnvironmentVariable("RoleRoot");

当我在已部署的实例上运行它时,我得到:

MapPath: E:\sitesroot\0\ RoleRoot:

即 RoleRoot 为空。

那么我怎样才能得到 Server.MapPath("~/"); 的结果?在启动任务中?

4

4 回答 4

3

为什么不相对得到呢?siterootapproot都部署到的驱动器似乎在 E:\ 和 F:\ 之间切换,但我认为现在假设它们将被部署为同级文件夹是一个更安全的选择。

这是我们从站点根文件夹复制文件的启动任务:

xcopy "../../sitesroot/0/bin" "../../sitesroot/1/bin" /y /i /S
xcopy "../../sitesroot/0/bin" "../../sitesroot/2/bin" /y /i /S
xcopy "../../sitesroot/0/bin" "../../sitesroot/3/bin" /y /i /S
xcopy "../../sitesroot/0/bin" "../../sitesroot/4/bin" /y /i /S
xcopy "../../sitesroot/0/bin" "../../sitesroot/5/bin" /y /i /S
于 2012-02-22T13:28:36.030 回答
3

不要在命令提示符下使用 icacls,而是使用 Powershell 脚本,因为 Powershell 允许您在 IIS 中枚举网站并获取物理文件夹路径。

不幸的是,您不能将 Powershell 脚本设置为启动任务。所以你必须创建一个常规的 CMD 或 BAT 文件,然后在这个文件中让 Powershell 执行你的脚本。

CMD 文件:

PowerShell -ExecutionPolicy Unrestricted .\Setup.ps1 >> %TEMP%\Setup-DebugLog.txt 2>&1
exit /B 0

第一行执行 Powershell 脚本并将所有输出保存到文件 Setup-DebugLog.txt。第二行确保 CMD 文件向 Windows Azure 返回一个 OK,因此 Azure 知道启动脚本中的一切正常。

这是我用来在 App_Data 文件夹上设置文件夹权限的 Powershell 脚本:

Import-Module WebAdministration
cd IIS:\Sites
$dir = Get-ChildItem
$timeout = 0
while ($dir -eq $NULL -and $timeout -lt 11)
{
    "IIS Site not ready. Waiting for 2 seconds..."
    [System.Threading.Thread]::Sleep(2000)
    $timeout++
    $dir = Get-ChildItem
}

if ($dir -eq $NULL)
{
    "IIS Site still not ready. Aborting."
}
else
{
    "IIS site ready."
    Set-Location $dir.physicalPath
    "Location is $($dir.physicalPath)"
    $acl = (Get-Item App_Data).GetAccessControl("Access")
    $rule = New-Object System.Security.AccessControl.FileSystemAccessRule("Network Service", "Modify, Write", "ContainerInherit, ObjectInherit", "None", "Allow")
    $acl.AddAccessRule($rule)
    Set-Acl App_Data $acl
    "Permission added."
}

它首先导入 WebAdministration 模块,该模块允许 Powershell 与 IIS 交互。然后它会尝试枚举网站。但是,这是一个有趣的挑战。因为,启动任务在您的网站部署到 IIS 之前运行。所以你需要将你的启动任务设置为后台任务运行,然后等到站点部署完毕。所以代码尝试枚举网站,如果没有找到网站,它会等待 2 秒,然后再试一次。它总共执行 20 秒,然后超时。如果网站准备就绪,则找到物理路径并将 FileSystemAccessRule 添加到 App_Data 文件夹的 ACL。您可以修改添加的权限以满足您的需要。请注意,此脚本预计 IIS 中只有 1 个站点。如果您部署超过 1 个网站,

为了完整起见,这里是您应该添加到您的 XML ServiceDefinition.csdef

<Startup>
  <Task commandLine="Setup.cmd" executionContext="elevated" taskType="background" />
</Startup>

两者都Setup.cmd应该Setup.ps1放在您网站的根目录中。如果您希望将它们放置在您网站的子文件夹中,您可以这样做,但是您必须将 Task 元素中的 commandLine 属性更新为“Subfolder\Setup.cmd”,并且您需要在 CMD 文件中更新 Powershell 文件的路径:

PowerShell -ExecutionPolicy Unrestricted .\Subfolder\Setup.ps1 >> %TEMP%\Setup-DebugLog.txt 2>&1

另外,请注意,Powershell v1 和 v2 在调用 Powershell 脚本方面存在一些差异。如果我没记错的话,Windows Azure 上的 Windows 2008 运行 Powershell v1,Windows 2008 R2 和更新版本运行 Powershell v2。因此,如果您在 Azure 上使用 Windows 2008,则需要更改调用 Powershell 脚本的行,因为在设置执行策略方面存在一些差异。

于 2013-06-03T10:16:56.587 回答
2

有一个名为 %ROLEROOT% 的环境变量用于获取应用程序的路径。

string appRoot = Environment.GetEnvironmentVariable("RoleRoot");

appRoot = Path.Combine(appRoot + @"\", @"approot\");

在此处阅读有关此内容的更多信息。

于 2011-06-18T16:19:39.877 回答
1

不,我不认为从启动任务中获取 Web 角色的网站根目录的方法。

于 2011-06-18T22:54:55.510 回答