4

Azure CDN に Azure Web サイトのテーマを格納する方法を実装しようとしています。

ファイルを 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

ムーチョグーグルは最終的にこの同様の問題を発見しました

タグ内の web.config に以下を追加した<system.webServer>ところ、イメージ ファイルと 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 に答える