Azure 云服务包 - 在托管 VSTS 构建服务器上找不到 Physical/Virtual 路径

Azure Cloud Service Package - Cant find Physical/Virtual Path on hosted VSTS build server

我在 VSTS 上使用托管构建代理来构建和部署云服务。

打包云服务时,cspack.exe报错找不到虚拟路径的物理目录。

....
  <WebRole name="MySite" vmsize="Small">
    <Sites>
      <Site name="Web">
        <VirtualDirectory name="media" physicalDirectory="Z:\MySiteMedia" />
        <Bindings>
....

ServiceDefinition.csdef: Error CloudServices079 : Cannot find the physical directory 'Z:\MySiteMedia' for virtual path Web/media/.

物理目录确实不存在于构建服务器上,但它存在于云服务将要部署到的服务器上。这是一个 Azure 文件共享。

有解决办法吗?

更新

可以在构建代理上创建一个虚拟驱动器,它具有所需的驱动器号和文件夹。该驱动器可能指向另一个本地驱动器。例如,Z:\ 可能指向 C:\

示例:

net use Z: \localhost\c$\MySiteMedia

这解决了构建问题,但是并没有解决实际问题。

经过一番挖掘,我发现cspack并没有像我最初想的那样工作。添加

<VirtualDirectory>

到 ServiceDefition,它获取该文件夹的内容并将其打包到 cspkg 文件中。然后它创建一个新文件夹,将其放置在 siteroot 文件夹中,然后为该新文件夹创建一个虚拟目录。

示例:

变成

这意味着将不会使用 Z:\ 上的 Azure 文件共享。

解决方法是在部署角色后使用 RoleEntryPoint 创建将虚拟目录添加到 IIS。

根据 Azure Docs,此属性定义内容存在于开发机器上的目录 - 或者您方案中的构建机器 - 而不是文件将放置在生产环境中的目录。

https://msdn.microsoft.com/en-us/library/azure/gg557553.aspx#Site

Required. Specifies the path on the development machine that contains the website or Virtual directory contents. In the compute emulator, IIS is configured to retrieve content from this location. When deploying to the Azure, the contents of the physical directory are packaged along with the rest of the service. When the service package is deployed to Azure, IIS is configured with the location of the unpacked contents.

我通过创建一个 RoleEntryPoint 解决了这个问题,它为我的角色运行初始化代码。这发生在角色部署之后。代码可以放在角色本身的任何文件夹中。

Microsoft.Web.Administration用于将虚拟目录添加到IIS。我在使用 NuGet 中的 Microsoft.Web.Administration 时遇到了一些问题,因为它引用了一个 CORE 项目,在部署到云服务时会出现运行时异常:

(System.IO.FileNotFoundException: Could not load file or assembly 'System.Runtime, Version=4.1.0.0, Culture=neutral..)

所以我从 C:\Windows\System32\inetsrv\ 引用了 Microsoft.Web.Administration.dll - 以获取在开发计算机上安装 IIS 所需的 DLL。

代码将虚拟目录添加到 IIS 上的第一个站点。这对我有用,如果您有多个站点,则需要根据需要进行修改。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.Web.Administration;
using Microsoft.WindowsAzure.ServiceRuntime;
using Newtonsoft.Json;

namespace MyNamespace.Azure
{
    public class WebRole : RoleEntryPoint
    {
        public override bool OnStart()
        {
            try
            {
                // Add initialization code here
                var serverManager = new ServerManager();
                var site = serverManager.Sites.First();
                var application = site.Applications.First();

                Trace.WriteLine($"First site: {site.Name} ");
                Trace.WriteLine($"First application path for site {site.Name}: {application.Path}");

                var vDirs = JsonConvert.DeserializeObject<Dictionary<string, string>>(File.ReadAllText(@"Azure\VirtualDirectories.json"));

                var vDirsToDelete = new List<VirtualDirectory>();
                foreach (var vDir in vDirs)
                {
                    var virtualDirectories = application.VirtualDirectories.Where(x => x.Path == vDir.Key).ToList();
                    vDirsToDelete.AddRange(virtualDirectories);
                }

                if (vDirsToDelete.Any())
                {
                    foreach (var vDir in vDirsToDelete)
                    {
                        Trace.WriteLine($"Removing existing media virtual directory");
                        application.VirtualDirectories.Remove(vDir);
                    }
                }

                foreach (var vDir in vDirs)
                {
                    Trace.WriteLine($"Adding virtual directory. Address: {vDir.Key}, PhysicalPath: {vDir.Value}");
                    application.VirtualDirectories.Add(vDir.Key, vDir.Value);
                }

                serverManager.CommitChanges();

            }
            catch (Exception e)
            {
                Trace.WriteLine("Exception during OnStart: " + e);
                // Take other action as needed.
            }

            return base.OnStart();
        }
    }
}

VirtualDirectories.json:

{
  "media": "Z:\MySiteMedia"
}