如何将捆绑和缩小的文件上载到Windows Azure CDN

Mar*_*erl 27 cdn azure asp.net-mvc-4 bundling-and-minification asp.net-optimization

我正在使用ASP.NET MVC 4捆绑和缩小Microsoft.AspNet.Web.Optimization命名空间中的功能(例如@Styles.Render("~/content/static/css")).

我想将它与Windows Azure CDN结合使用.

我考虑编写自定义,BundleTransform但内容尚未优化.

我还研究了在运行时解析和上传优化的流,但这对我来说就像是一个黑客,我真的不喜欢它:

@StylesCdn.Render(Url.AbsoluteContent(
    Styles.Url("~/content/static/css").ToString()
    ));

public static IHtmlString Render(string absolutePath)
{
    // get the version hash
    string versionHash = HttpUtility.ParseQueryString(
        new Uri(absolutePath).Query
        ).Get("v");

    // only parse and upload to CDN if version hash is different
    if (versionHash != _versionHash)
    {
        _versionHash = versionHash;

        WebClient client = new WebClient();
        Stream stream = client.OpenRead(absolutePath);

        UploadStreamToAzureCdn(stream);
    }

    var styleSheetLink = String.Format(
        "<link href=\"{0}://{1}/{2}/{3}?v={4}\" rel=\"stylesheet\" type=\"text/css\" />",
        cdnEndpointProtocol, cdnEndpointUrl, cdnContainer, cdnCssFileName, versionHash
        );

    return new HtmlString(styleSheetLink);
}
Run Code Online (Sandbox Code Playgroud)

如何将捆绑和缩小的版本自动上传到我的Windows Azure CDN?

Dan*_*lin 18

遵循郝的建议我扩展捆绑和IBundleTransform.

将AzureScriptBundle或AzureStyleBundle添加到包中;

bundles.Add(new AzureScriptBundle("~/bundles/modernizr.js", "cdn").Include("~/Scripts/vendor/modernizr.custom.68789.js"));
Run Code Online (Sandbox Code Playgroud)

结果是;

<script src="//127.0.0.1:10000/devstoreaccount1/cdn/modernizr.js?v=g-XPguHFgwIb6tGNcnvnI_VY_ljCYf2BDp_NS5X7sAo1"></script>
Run Code Online (Sandbox Code Playgroud)

如果没有设置CdnHost,它将使用blob的Uri而不是CDN.

using System;
using System.Text;
using System.Web;
using System.Web.Optimization;
using System.Security.Cryptography;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure.StorageClient;

namespace SiegeEngineWebRole.BundleExtentions
{
    public class AzureScriptBundle : Bundle
    {
        public AzureScriptBundle(string virtualPath, string containerName, string cdnHost = "")
            : base(virtualPath, null, new IBundleTransform[] { new JsMinify(), new AzureBlobUpload { ContainerName = containerName, CdnHost = cdnHost } })
        {
            ConcatenationToken = ";";
        }
    }

    public class AzureStyleBundle : Bundle
    {
        public AzureStyleBundle(string virtualPath, string containerName, string cdnHost = "")
            : base(virtualPath, null, new IBundleTransform[] { new CssMinify(), new AzureBlobUpload { ContainerName = containerName, CdnHost = cdnHost } })
        {
        }
    }

    public class AzureBlobUpload : IBundleTransform
    {
        public string ContainerName { get; set; }
        public string CdnHost { get; set; }

        static AzureBlobUpload()
        {
        }

        public virtual void Process(BundleContext context, BundleResponse response)
        {
            var file = VirtualPathUtility.GetFileName(context.BundleVirtualPath);

            if (!context.BundleCollection.UseCdn)
            {
                return;
            }
            if (string.IsNullOrWhiteSpace(ContainerName))
            {
                throw new Exception("ContainerName Not Set");
            }

            var conn = CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue("DataConnectionString"));
            var blob = conn.CreateCloudBlobClient()
                .GetContainerReference(ContainerName)
                .GetBlobReference(file);

            blob.Properties.ContentType = response.ContentType;
            blob.UploadText(response.Content);

            var uri = string.IsNullOrWhiteSpace(CdnHost) ? blob.Uri.AbsoluteUri.Replace("http:", "").Replace("https:", "") : string.Format("//{0}/{1}/{2}", CdnHost, ContainerName, file);

            using (var hashAlgorithm = CreateHashAlgorithm())
            {
                var hash = HttpServerUtility.UrlTokenEncode(hashAlgorithm.ComputeHash(Encoding.Unicode.GetBytes(response.Content)));
                context.BundleCollection.GetBundleFor(context.BundleVirtualPath).CdnPath = string.Format("{0}?v={1}", uri, hash);
            }
        }

        private static SHA256 CreateHashAlgorithm()
        {
            if (CryptoConfig.AllowOnlyFipsAlgorithms)
            {
                return new SHA256CryptoServiceProvider();
            }

            return new SHA256Managed();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Hao*_*ung 14

所以目前没有很好的方法可以做到这一点.我们设想的长期工作流程是添加构建时捆绑支持.然后,您将运行构建任务(或运行exe,如果您愿意)生成包,然后能够将这些上载到AzureCDN.最后,您只需打开BundleCollection上的UseCDN,脚本/样式助手就会自动切换到渲染到AzureCDN的链接,并正确回退到本地捆绑包.

从短期来看,我认为你要做的是在首次构建软件包时将软件包上传到AzureCDN?

一个BundleTransform是做这件事我想,它的一个黑客位的,但你可以在你的包添加BundleTransform最后.从最后一次开始,BundleResponse.Content实际上是最终的bundle响应.在那个时间点,您可以将其上传到您的CDN.那有意义吗?