4

我正在尝试将 Azure 网站的主题存储在 Azure CDN 中。

我已将文件复制到 CDN 中,并保留了原始 App_Themes 文件夹中的文件夹结构。

我创建了一个 VirtualPathProvider 以及必要的 Virtualdirectory 和 VirtualFile 类。提供者在 global.asax 中注册。

我的问题是似乎来自 CDN 的唯一文件是皮肤文件。所有图像、css 等仍然被引用,就好像它们在标准 App_Themes 结构中一样。如果我在我的代码中设置一个断点,那么我的 VirtualTheme 的 Open 方法只会为皮肤文件调用。

有没有人设法实施这样的解决方案?

任何想法我做错了什么?

[AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Medium)]
[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.High)]
public class RedirectAppThemes : VirtualPathProvider
{

    private bool IsPathVirtual(string virtualPath)
    {
        String checkPath = VirtualPathUtility.ToAppRelative(virtualPath);
        return checkPath.StartsWith("~/App_Themes/", StringComparison.InvariantCultureIgnoreCase);
    }

    public override bool FileExists(string virtualPath)
    {
        if (IsPathVirtual(virtualPath))
        {
            VirtualThemeFile file = new VirtualThemeFile(virtualPath);
            return file.Exists;
        }
        else
        {
            return Previous.FileExists(virtualPath);
        }
    }

    public override VirtualFile GetFile(string virtualPath)
    {
        if (IsPathVirtual(virtualPath))
        {
            return new VirtualThemeFile(virtualPath);
        }
        else
        {
            return Previous.GetFile(virtualPath);
        }
    }

    public override bool DirectoryExists(string virtualDir)
    {
        if (IsPathVirtual(virtualDir))
        {
            VirtualThemeDirectory dir = new VirtualThemeDirectory(virtualDir);
            return dir.Exists;
        }
        else
        {
            return Previous.DirectoryExists(virtualDir);
        }
    }

    public override VirtualDirectory GetDirectory(string virtualDir)
    {
        if (IsPathVirtual(virtualDir))
        {
            return new VirtualThemeDirectory(virtualDir);
        }
        else
        {
            return Previous.GetDirectory(virtualDir);
        }
    }

    public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart)
    {
        if (IsPathVirtual(virtualPath))
        {
            return null;
        }
        else
        {
            return Previous.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
        }
    }


}

 [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
public class VirtualThemeDirectory : VirtualDirectory
{
    private string cdnPath = "http://xxxxxxxxx.blob.core.windows.net/";

    public VirtualThemeDirectory(string virtualPath) : base(virtualPath)
    {
    }

    public override IEnumerable Children
    {
        get
        {
            List<object> children = new List<object>();

            string dir = this.VirtualPath.Replace("/App_Themes/", String.Empty);
            CloudBlobClient client = new CloudBlobClient(cdnPath);

            var blobs = client.ListBlobsWithPrefix(@"webinterfacethemes/" + dir );

            foreach (CloudBlobDirectory directory in blobs.OfType<CloudBlobDirectory>())
            {
                VirtualThemeDirectory vtd = new VirtualThemeDirectory(directory.Uri.AbsolutePath.Replace("/webinterfacethemes/", "/App_Themes/"));
                children.Add(vtd);
            }
            foreach (CloudBlob file in blobs.OfType<CloudBlob>())
            {
                VirtualThemeFile vtf = new VirtualThemeFile(file.Uri.AbsolutePath.Replace("/webinterfacethemes/", "/App_Themes/"));
                children.Add(vtf);
            }                

            return children;
        }
    }

    public override IEnumerable Directories
    {
        get
        {
            List<object> children = new List<object>();

            string dir = this.VirtualPath.Replace("/App_Themes/", String.Empty);
            CloudBlobClient client = new CloudBlobClient(cdnPath);

            var blobs = client.ListBlobsWithPrefix(@"webinterfacethemes/" + dir);

            foreach (CloudBlobDirectory directory in blobs.OfType<CloudBlobDirectory>())
            {
                VirtualThemeDirectory vtd = new VirtualThemeDirectory(directory.Uri.AbsolutePath.Replace("/webinterfacethemes/", "/App_Themes/"));
                children.Add(vtd);
            }

            return children;
        }
    }

    public override IEnumerable Files
    {
        get
        {
            List<object> children = new List<object>();

            string dir = this.VirtualPath.Replace("/App_Themes/", String.Empty);
            CloudBlobClient client = new CloudBlobClient(cdnPath);

            var blobs = client.ListBlobsWithPrefix(@"webinterfacethemes/" + dir);

            foreach (CloudBlob file in blobs.OfType<CloudBlob>())
            {
                VirtualThemeFile vtf = new VirtualThemeFile(file.Uri.AbsolutePath.Replace("/webinterfacethemes/", "/App_Themes/"));
                children.Add(vtf);
            }

            return children;
        }
    }

    public bool Exists
    {
        get
        {
            string dir = this.VirtualPath.Replace("/App_Themes/", String.Empty);
            CloudBlobClient client = new CloudBlobClient(cdnPath);

            if (client.ListBlobsWithPrefix("webinterfacethemes/" + dir).Count() > 0)
                return true;
            else
                return false;

        }
    }
}

[AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
public class VirtualThemeFile : VirtualFile
{
    private string cdnPath = "http://xxxxxxx.vo.msecnd.net/webinterfacethemes/";

    public VirtualThemeFile(string VirtualPath) : base(VirtualPath)
    {

    }

    public override Stream Open()
    {
        string url = this.VirtualPath.Replace("/App_Themes/", cdnPath);
        HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(url);
        WebResponse myResp = myReq.GetResponse();
        Stream stream = myResp.GetResponseStream();
        return stream;
    }

    public bool Exists
    {
        get
        {
            //Check if the file exists
            //do this with a HEAD only request so we don't download the whole file
            string url = this.VirtualPath.Replace("/App_Themes/", cdnPath);
            HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(url);
            myReq.Method = "HEAD";
            HttpWebResponse myResp = (HttpWebResponse)myReq.GetResponse();
            if (myResp.StatusCode == HttpStatusCode.OK)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}

在 Global.asax Application_start 中:

RedirectAppThemes redirect = new RedirectAppThemes();
        HostingEnvironment.RegisterVirtualPathProvider(redirect);
4

1 回答 1

3

Mucho Googling 最终发现了这个类似的问题

我已将以下内容添加到<system.webServer>标签内的 web.config 中,现在图像和 css 文件正在调用我的代码中的方法。

<handlers>
  <add name="Images" path="*.png" verb="GET,HEAD,POST" type="System.Web.StaticFileHandler" modules="ManagedPipelineHandler" resourceType="Unspecified" />
  <add name="Stylesheets" path="*.css" verb="GET,HEAD,POST" type="System.Web.StaticFileHandler" modules="ManagedPipelineHandler" resourceType="Unspecified" />
</handlers>

如果有人正在寻找一个完整的解决方案来使用这种方法将他们的主题放入 CDN,我还从上面发布的原始代码中更改了以下内容,现在它可以工作了:

VirtualFile 类如下:

[AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
public class VirtualThemeFile : VirtualFile
{
    private string cdnPath = "https://xxxxxx.vo.msecnd.net/webinterfacethemes/";
    private string blobURL;

    public VirtualThemeFile(string VirtualPath) : base(VirtualPath)
    {
        blobURL = this.VirtualPath.Replace("/App_Themes/", cdnPath);
    }

    public override Stream Open()
    {
        CloudBlobClient client = new CloudBlobClient(cdnPath);
        CloudBlob blob = client.GetBlobReference(blobURL);
        MemoryStream stream = new MemoryStream();
        blob.DownloadToStream(stream);
        stream.Seek(0, SeekOrigin.Begin);
        return stream;
    }

    public bool Exists
    {
        get
        {
            CloudBlobClient client = new CloudBlobClient(cdnPath);
            CloudBlob blob = client.GetBlobReference(blobURL);
            try
            {
                blob.FetchAttributes();
                return true;
            }
            catch (StorageClientException e)
            {
                if (e.ErrorCode == StorageErrorCode.ResourceNotFound)
                {
                    return false;
                }
                else
                {
                    throw;
                }
            }
        }
    }
}

而且我已经更改了我的 global.asax 代码,以便在预编译站点时调用 VirtualPathProvider:

HostingEnvironment hostingEnvironmentInstance = (HostingEnvironment)typeof(HostingEnvironment).InvokeMember("_theHostingEnvironment", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetField, null, null, null);
        MethodInfo mi = typeof(HostingEnvironment).GetMethod("RegisterVirtualPathProviderInternal", BindingFlags.NonPublic | BindingFlags.Static);
        mi.Invoke(hostingEnvironmentInstance, new object[] { new RedirectAppThemes() });
于 2011-11-18T08:58:12.067 回答