【问题标题】:Using VirtualPathProvider to put Themes in Azure CDN使用 VirtualPathProvider 将主题放入 Azure CDN
【发布时间】:2012-08-09 06:17:18
【问题描述】:

我正在尝试将 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);

【问题讨论】:

  • 不确定是否相关,但请尝试: 我的猜测是对常规 css/图像文件的请求不会通过 ASP.NET 管道如果未启用此设置,则根本没有。
  • 我已经设置了该设置,以便运行另一个允许在母版页级别设置主题的模块。
  • 我想我不明白的一点是,当设置页面主题(在 Pre-init 中)时,它如何设置样式表的 URL 等。目前它似乎只是写入aspx 文件的路径为 而不是通过我的提供程序来获取文件的路径CDN?
  • 但是浏览器发出的“../App_Themes/OtherThemeCopy/Site.css”请求应该通过VPP...
  • 是的。我的问题是它似乎没有?

标签: azure themes virtualpathprovider azure-cdn


【解决方案1】:

Mucho 谷歌搜索最终找到了这个similar problem

我已在 &lt;system.webServer&gt; 标记内的 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-06-05
    • 1970-01-01
    • 1970-01-01
    • 2011-08-01
    • 2020-05-24
    • 1970-01-01
    • 2013-05-28
    • 2021-03-16
    • 1970-01-01
    相关资源
    最近更新 更多