使用 VirtualPathProvider 将主题放入 Azure CDN
我正在尝试实现将 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);
I'm trying to implement storing an Azure web site's Themes in the Azure CDN.
I've copied the files into the CDN retaining the folder structure as it was in the original App_Themes folder.
I've created a VirtualPathProvider and the necessary Virtualdirectory and VirtualFile classes. The provider is registered in global.asax.
My problem is that the only file that seems to come from the CDN is the skin file. All the images, css etc are still refernced as if they are in the standard App_Themes structure. If I put a break point in my code then my VirtualTheme's Open method is only ever called for the skin file.
Has anyone managed to implement a solution like this?
Any ideas what I'm doing wrong?
[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;
}
}
}
}
And in Global.asax Application_start:
RedirectAppThemes redirect = new RedirectAppThemes();
HostingEnvironment.RegisterVirtualPathProvider(redirect);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Mucho 谷歌搜索最终发现了这个类似问题
我已将以下内容添加到我的网站中。在
标记内进行配置,现在图像和 css 文件正在调用我的代码中的方法。如果有人正在寻找使用此方法将其主题放入 CDN 的完整解决方案,我还对上面发布的原始代码进行了以下更改,现在它可以工作了:
VirtualFile 类如下:
并且我已经更改了我的全局.asax 代码,以便在预编译站点时调用 VirtualPathProvider:
Mucho Googling eventually found this similar problem
I've added the following to my web.config inside the
<system.webServer>
tags and now the image and css files are calling the methods in my code.If anyone is looking for a complete solution to putting their Themes in the CDN using this method I've also changed the following from the original code posted above and it now works:
the VirtualFile class is as follows:
And I've changed my global.asax code so that the VirtualPathProvider is invoked if the site is pre-compiled: