56

私はMVCアプリケーションを持っており、次のStyleBundleようなCSSファイルをレンダリングするためにクラスを使用しています。

bundles.Add(new StyleBundle("~/bundles/css").Include("~/Content/*.css"));

私が抱えている問題は、Debugモードでは、CSS URLが個別にレンダリングされ、これらのURLを積極的にキャッシュするWebプロキシがあることです。モードではRelease、リリースごとにキャッシュを無効にするために、クエリ文字列が最終URLに追加されることを知っています。

キャッシュの問題を回避するために、モードStyleBundleでランダムなクエリ文字列を追加して次の出力を生成するように構成することは可能ですか?Debug

<link href="/stylesheet.css?random=some_random_string" rel="stylesheet"/>
4

6 に答える 6

48

これを行うために、カスタム IBundleTransform クラスを作成できます。ファイルの内容のハッシュを使用して av=[filehash] パラメータを追加する例を次に示します。

public class FileHashVersionBundleTransform: IBundleTransform
{
    public void Process(BundleContext context, BundleResponse response)
    {
        foreach(var file in response.Files)
        {
            using(FileStream fs = File.OpenRead(HostingEnvironment.MapPath(file.IncludedVirtualPath)))
            {
                //get hash of file contents
                byte[] fileHash = new SHA256Managed().ComputeHash(fs);

                //encode file hash as a query string param
                string version = HttpServerUtility.UrlTokenEncode(fileHash);
                file.IncludedVirtualPath = string.Concat(file.IncludedVirtualPath, "?v=", version);
            }                
        }
    }
}

その後、バンドルの Transforms コレクションにクラスを追加して、クラスを登録できます。

new StyleBundle("...").Transforms.Add(new FileHashVersionBundleTransform());

バージョン番号は、ファイルの内容が変更された場合にのみ変更されます。

于 2014-10-21T15:32:24.480 に答える
9

私は同じ問題を抱えていましたが、アップグレード後にクライアント ブラウザーにキャッシュされたバージョンがありました。@Styles.Render("~/Content/css")私の解決策は、次のようにクエリ文字列にバージョン番号を追加する独自のレンダラーで呼び出しをラップすることです。

    public static IHtmlString RenderCacheSafe(string path)
    {
        var html = Styles.Render(path);
        var version = VersionHelper.GetVersion();
        var stringContent = html.ToString();

        // The version should be inserted just before the closing quotation mark of the href attribute.
        var versionedHtml = stringContent.Replace("\" rel=", string.Format("?v={0}\" rel=", version));
        return new HtmlString(versionedHtml);
    }

そして、ビューで私はこれが好きです:

@RenderHelpers.RenderCacheSafe("~/Content/css")
于 2014-03-14T08:27:06.747 に答える
2

現在はありませんが、これはまもなく追加される予定です (現在、1.1 の安定版リリースが予定されています。この問題はこちらで追跡できます: Codeplex

于 2013-02-22T11:05:51.153 に答える
1

これはスクリプト用に書かれていますが、スタイルでも機能することに注意してください(これらのキーワードを変更するだけです)

@ Johanの答えに基づいて構築:

public static IHtmlString RenderBundle(this HtmlHelper htmlHelper, string path)
{
    var context = new BundleContext(htmlHelper.ViewContext.HttpContext, BundleTable.Bundles, string.Empty);
    var bundle = System.Web.Optimization.BundleTable.Bundles.GetBundleFor(path);
    var html = System.Web.Optimization.Scripts.Render(path).ToString();
    foreach (var item in bundle.EnumerateFiles(context))
    {
        if (!html.Contains(item.Name))
            continue;

        html = html.Replace(item.Name, item.Name + "?" + item.LastWriteTimeUtc.ToString("yyyyMMddHHmmss"));
    }

    return new HtmlString(html);
}

public static IHtmlString RenderStylesBundle(this HtmlHelper htmlHelper, string path)
{
    var context = new BundleContext(htmlHelper.ViewContext.HttpContext, BundleTable.Bundles, string.Empty);
    var bundle = System.Web.Optimization.BundleTable.Bundles.GetBundleFor(path);
    var html = System.Web.Optimization.Styles.Render(path).ToString();
    foreach (var item in bundle.EnumerateFiles(context))
    {
        if (!html.Contains(item.Name))
            continue;

        html = html.Replace(item.Name, item.Name + "?" + item.LastWriteTimeUtc.ToString("yyyyMMddHHmmss"));
    }

    return new HtmlString(html);
}

使用法:

@Html.RenderBundle("...")
@Html.RenderStylesBundle("...")

交換する

@Scripts.Render("...")
@Styles.Render("...")

利点:

  • System.Web.Optimizations の v1.0.0.0 で動作します
  • バンドル内の複数のファイルで動作
  • グループではなく、各ファイルのハッシュではなく、ファイルの変更日を取得します

また、Bundler をすばやく回避する必要がある場合:

public static MvcHtmlString ResolveUrl(this HtmlHelper htmlHelper, string url)
{
    var urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext);
    var resolvedUrl = urlHelper.Content(url);

    if (resolvedUrl.ToLower().EndsWith(".js") || resolvedUrl.ToLower().EndsWith(".css"))
    {
        var localPath = HostingEnvironment.MapPath(resolvedUrl);
        var fileInfo = new FileInfo(localPath);
        resolvedUrl += "?" + fileInfo.LastWriteTimeUtc.ToString("yyyyMMddHHmmss");
    }

    return MvcHtmlString.Create(resolvedUrl);
}

使用法:

<script type="text/javascript" src="@Html.ResolveUrl("~/Scripts/jquery-1.9.1.min.js")"></script>

交換:

<script type="text/javascript" src="@Url.Content("~/Scripts/jquery-1.9.1.min.js")"></script>

(他の多くの代替ルックアップも置き換えます)

于 2016-03-19T13:20:36.230 に答える