使用ASP.NET 4.5 Bundling& CDN(例如CloudFront)

时间:2012-11-14 09:46:34

标签: c# amazon-cloudfront asp.net-4.5 bundling-and-minification

ASP.NET 4.5具有很好的新捆绑功能,似乎对CDN的使用有一些支持。 Microsoft提供的使用CDN捆绑功能的示例是

public static void RegisterBundles(BundleCollection bundles)
{
  //bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
  //            "~/Scripts/jquery-{version}.js"));

  bundles.UseCdn = true;   //enable CDN support

  //add link to jquery on the CDN
  var jqueryCdnPath = "http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js";

  bundles.Add(new ScriptBundle("~/bundles/jquery",
            jqueryCdnPath).Include(
            "~/Scripts/jquery-{version}.js"));

  // Code removed for clarity.
} 

这似乎暗示您需要明确告诉它CDN上文件的路径。

CloudFront CDN(我假设许多其他人)为您提供了一个镜像您自己的子域。当您点击http://uniquesubdomain.cloudfront.net/js/myfile.js?v=1时,它会提供http://mydomain.com/js/myfile.js?v=1

这样您就可以使用http://uniquesubdomain.cloudfront.net/为所有链接添加前缀,并且您的文件是来自CloudFront的服务器。

ASP.NET 4.5捆绑功能是否与此类CDN兼容?是否有内置方法可以将捆绑功能的所有链接作为CDN域的前缀?

EG。

bundles.UseCdn = true;
var myBundle= new ScriptBundle("~/bundles/js", "https://uniquedomain.cloudfront.net/");
myBundle.Include("~/js/file1.js");
myBundle.Include("~/js/file2.js");

会导致

    <script src="https://uniquedomain.cloudfront.net/bundles/js?v=6y-qVPSK3RYOYHfPhOBDd92H4LjEjs-D3Hh2Yml6CXA1"></script>

4 个答案:

答案 0 :(得分:9)

此功能不是内置的,但可以使用几个小帮助方法。这就是我现在正在使用的内容:

public static class Cdn
{
    private const string CdnRoot = "//cloudfrontdomainhere.com";

    private static bool EnableCdn
    {
        get
        {
            bool enableCdn = false;
            bool.TryParse(WebConfigurationManager.AppSettings["EnableCdn"], out enableCdn);
            return enableCdn;
        }
    }

    public static IHtmlString RenderScripts(string bundlePath)
    {
        if (EnableCdn)
        {
            string sourceUrl = CdnRoot + Scripts.Url(bundlePath);
            return new HtmlString(string.Format("<script src=\"{0}\"></script>", sourceUrl));
        }

        return Scripts.Render(bundlePath);
    }

    public static IHtmlString RenderStyles(string bundlePath)
    {
        if (EnableCdn)
        {
            string sourceUrl = CdnRoot + Styles.Url(bundlePath);
            return new HtmlString(string.Format("<link href=\"{0}\" rel=\"stylesheet\" />", sourceUrl));
        }

        return Styles.Render(bundlePath);
    }
}

请注意,我的配置文件的appSettings部分中有自己的配置设置EnableCdn。从Razor视图调用时,会产生正确的输出,将CDN域附加到路径上。

在您的Razor文件中,只需执行Cdn.RenderScripts(“〜/ pathtoscriptbundle”)

答案 1 :(得分:1)

可能不是您正在寻找的,但很多CDN现在充当使用DNS的反向代理,因此您无需明确链接您的资产。我知道Cloudflare这样做,我相信其他人也会这样做。

答案 2 :(得分:1)

另一个选择是使用Scripts或Styles RenderFormat方法。这对我来说特别有用,因为我偶尔自定义tagFormat以在条件html注释中包装引用,或附加其他属性,如media =“screen,print”。代码更简单,因为你可以在它变成HTML编码的字符串之前对字符串进行尴尬的替换。

或者,您可以将tagFormat作为这些方法的可选参数,其中默认值是下面提到的字符串常量。

public class BundleHelper
{
    public static readonly string StyleTagFormat = "<link href=\"{0}\" rel=\"stylesheet\"/>";
    public static readonly string ScriptTagFormat = "<script src=\"{0}\"></script>"

    /// <summary>
    /// Customised script bundle rendering method with CDN support if optimizations and CDN enabled.
    /// </summary>
    public static IHtmlString RenderScriptFormat(string tagFormat, string path)
    {
        // Check for absolute url to ensure the standard framework support for CDN bundles, with a CdnPath still works.
        if (AppSettings.Bundling.EnableCdn && !UriHelper.IsAbsoluteUrl(Scripts.Url(path).ToString()))
        {
            tagFormat = tagFormat.Replace(" src=\"{0}\"", String.Format(" src=\"{0}{{0}}\"", AppSettings.Bundling.BundlesCDNPrefixUrl));
        }
        return Scripts.RenderFormat(tagFormat, path);
    }

    /// <summary>
    /// Customised styles bundle rendering method with CDN support if optimizations and CDN enabled.
    /// </summary>
    public static IHtmlString RenderStyleFormat(string tagFormat, string path)
    {
        // Check for absolute url to ensure the standard framework support for CDN bundles, with a CdnPath still works.
        if (AppSettings.Bundling.EnableCdn && !UriHelper.IsAbsoluteUrl(Styles.Url(path).ToString()))
        {
            tagFormat = tagFormat.Replace(" href=\"{0}\"", String.Format(" href=\"{0}{{0}}\"", AppSettings.Bundling.BundlesCDNPrefixUrl));
        }
        return Styles.RenderFormat(tagFormat, path);
    }
}


public class UriHelper
{
    /// <summary>
    /// Determines whether a url is absolute or not.
    /// </summary>
    /// <param name="url">Url string  to test.</param>
    /// <returns>true/false.</returns>
    /// <remarks>
    /// Examples:
    ///     ?IsAbsoluteUrl("hello")
    ///     false
    ///     ?IsAbsoluteUrl("/hello")
    ///     false
    ///     ?IsAbsoluteUrl("ftp//hello")
    ///     false
    ///     ?IsAbsoluteUrl("//hello")
    ///     true
    ///     ?IsAbsoluteUrl("ftp://hello")
    ///     true
    ///     ?IsAbsoluteUrl("http://hello")
    ///     true
    ///     ?IsAbsoluteUrl("https://hello")
    ///     true
    /// </remarks>
    public static bool IsAbsoluteUrl(string url)
    {
        Uri result;
        return Uri.TryCreate(url, UriKind.Absolute, out result);
    }
}

答案 3 :(得分:0)

这是不可能的,但是你可以使用文本模板将JS文件组合为一个js并将其放在CDN上而不是bundle。

<#@ ... hostspecific="true"  extension=".js">

<#

    Write (System.IO.File.ReadAllText("a.js"));
    Write (System.IO.File.ReadAllText("b.js"));
 #>