How to upload bundled and minified files to Windows Azure CDN

前端 未结 4 1569
感动是毒
感动是毒 2020-12-07 16:50

I\'m using the ASP.NET MVC 4 bundling and minifying features in the Microsoft.AspNet.Web.Optimization namespace (e.g. @Styles.Render(\"~/content/static/css\")).

相关标签:
4条回答
  • 2020-12-07 17:22

    For @manishKungwani requested in previous comment. Just set UseCdn and then use the cdnHost overload to crate the bundle. I used this to put in an AWS CloudFront domain (xxx.cloudfront.net) but in hindsight it should have been named more generically to use with any other CDN provider.

    public class CloudFrontScriptBundle : Bundle
    {
        public CloudFrontScriptBundle(string virtualPath, string cdnHost = "")
            : base(virtualPath, null, new IBundleTransform[] { new JsMinify(), new CloudFrontBundleTransformer { CdnHost = cdnHost } })
        {
            ConcatenationToken = ";";
        }
    }
    
    public class CloudFrontStyleBundle : Bundle
    {
        public CloudFrontStyleBundle(string virtualPath, string cdnHost = "")
            : base(virtualPath, null, new IBundleTransform[] { new CssMinify(), new CloudFrontBundleTransformer { CdnHost = cdnHost } })
        {
        }
    }
    
    public class CloudFrontBundleTransformer : IBundleTransform
    {
        public string CdnHost { get; set; }
    
        static CloudFrontBundleTransformer()
        {
        }
    
        public virtual void Process(BundleContext context, BundleResponse response)
        {
            if (context.BundleCollection.UseCdn && !String.IsNullOrWhiteSpace(CdnHost))
            {
                var virtualFileName = VirtualPathUtility.GetFileName(context.BundleVirtualPath);
                var virtualDirectory = VirtualPathUtility.GetDirectory(context.BundleVirtualPath);
    
                if (!String.IsNullOrEmpty(virtualDirectory))
                    virtualDirectory = virtualDirectory.Trim('~');
    
                var uri = string.Format("//{0}{1}{2}", CdnHost, virtualDirectory, virtualFileName);
                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();
        }
    }
    
    0 讨论(0)
  • 2020-12-07 17:38

    You can define origin domain as Azure's website (this probably was added long after the original question).

    Once you have CDN endpoint, you will need to allow query string for it and then you can reference directly to bundles via CDN:

    <link href="//az888888.vo.msecnd.net/Content/css-common?v=ioYVnAg-Q3qYl3Pmki-qdKwT20ESkdREhi4DsEehwCY1" rel="stylesheet"/>
    

    I've also created this helper to append CDN host name:

    public static IHtmlString RenderScript(string virtualPath)
    {
        if (HttpContext.Current.IsDebuggingEnabled)
            return Scripts.Render(virtualPath);
        else
            return new HtmlString(String.Format(
                CultureInfo.InvariantCulture, 
                Scripts.DefaultTagFormat, 
                "//CDN_HOST" + Scripts.Url(virtualPath).ToHtmlString()));
    }
    
    0 讨论(0)
  • 2020-12-07 17:45

    Following Hao's advice I Extended Bundle and IBundleTransform.

    Adding AzureScriptBundle or AzureStyleBundle to bundles;

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

    Results in;

    <script src="//127.0.0.1:10000/devstoreaccount1/cdn/modernizr.js?v=g-XPguHFgwIb6tGNcnvnI_VY_ljCYf2BDp_NS5X7sAo1"></script>
    

    If CdnHost isn't set it will use the Uri of the blob instead of the CDN.

    Class

    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();
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-07 17:46

    So there isn't a great way to do this currently. The longer term workflow we are envisioning is adding build-time bundling support. Then you would run a build task (or run an exe if you prefer) to generate the bundles and then be able to upload these to the AzureCDN. Finally, you just turn on UseCDN on the BundleCollection, and the Script/Style helpers would just automatically switch to rendering out links to your AzureCDN with proper fallback to your local bundles.

    For the short term, what I think you are trying to do is upload your bundle to the AzureCDN when the bundle is first constructed?

    A BundleTransform is one way to do it I guess, its a bit of a hack, but you could add a BundleTransform last in your bundle. Since its last, the BundleResponse.Content is effectively the final bundle response. At that point in time you can upload it to your CDN. Does that make sense?

    0 讨论(0)
提交回复
热议问题