87

... または、心配するのをやめて、Microsoft の完全に文書化されていない API に対してコードを書くことを学んだ方法. 公式System.Web.Optimizationリリースの実際のドキュメントはありますか? XMLドキュメントはなく、すべてのブログ投稿は実質的に異なるRC APIを参照しています。どーも..

JavaScript の依存関係を自動的に解決するコードを書いており、それらの依存関係からオンザフライでバンドルを作成しています。スクリプトを編集したり、アプリケーションを再起動せずにバンドルに影響を与えるような変更を加えたりした場合を除いて、すべてがうまく機能します。変更は反映されません。そこで、開発で使用する依存関係のキャッシュを無効にするオプションを追加しました。

ただし、バンドル コレクションが変更された場合でも、明らかBundleTablesに URL をキャッシュします。たとえば、自分のコードでバンドルを再作成する場合は、次のようにします。

// remove an existing bundle
BundleTable.Bundles.Remove(BundleTable.Bundles.GetBundleFor(bundleAlias));

// recreate it.
var bundle = new ScriptBundle(bundleAlias);

// dependencies is a collection of objects representing scripts, 
// this creates a new bundle from that list. 

foreach (var item in dependencies)
{
    bundle.Include(item.Path);
}

// add the new bundle to the collection

BundleTable.Bundles.Add(bundle);

// bundleAlias is the same alias used previously to create the bundle,
// like "~/mybundle1" 

var bundleUrl = BundleTable.Bundles.ResolveBundleUrl(bundleAlias);

// returns something like "/mybundle1?v=hzBkDmqVAC8R_Nme4OYZ5qoq5fLBIhAGguKa28lYLfQ1"

同じエイリアスを持つバンドルを削除して再作成するたびに、まったく何も起こりません。bundleUrl返される fromResolveBundleUrlは、バンドルを削除して再作成する前と同じです。「同じ」とは、バンドルの新しいコンテンツを反映するために、コンテンツ ハッシュが変更されていないことを意味します。

編集...実際には、それよりもはるかに悪いです。バンドル自体は、何らかの方法でBundlesコレクションの外にキャッシュされます。ブラウザがスクリプトをキャッシュしないように独自のランダム ハッシュを生成しただけでは、ASP.NET は古いスクリプトを返します。したがって、明らかに、からバンドルを削除しBundleTable.Bundlesても実際には何も起こりません。

この問題を回避するためにエイリアスを変更するだけで済みます。これは開発には問題ありませんが、ページの読み込みごとにエイリアスを非推奨にするか、BundleCollection のサイズが大きくなる必要があるため、この考えは好きではありません。すべてのページの読み込み。これを本番環境でそのままにしておくと、大変なことになります。

BundleTables.Bundlesそのため、スクリプトが提供されると、実際のオブジェクトとは無関係にキャッシュされるようです。そのため、URL を再利用する場合、再利用する前にそれが参照していたバンドルを削除したとしても、キャッシュ内にあるもので応答し、Bundlesオブジェクトを変更してもキャッシュはフラッシュされません。つまり、新しいアイテム (またはむしろ、別の名前の新しいアイテム) が使用されることになります。

動作は奇妙に思えます...コレクションから何かを削除すると、キャッシュから削除されます。しかし、そうではありません。このキャッシュをフラッシュしてBundleCollection、そのバンドルが最初にアクセスされたときにキャッシュされたものの代わりに現在のコンテンツを使用する方法が必要です。

どうすればこれを行うことができますか?

ResetAll目的が不明なこのメソッドがありますが、とにかく物事を壊すだけなので、そうではありません。

4

6 に答える 6

34

ドキュメントに対する苦痛を聞いていますが、残念ながら、この機能はまだ非常に速く変化しており、ドキュメントの生成には多少の遅れがあり、ほとんどすぐに古くなる可能性があります。 Rickのブログ投稿は最新のものであり、その間に現在の情報を広めるために、ここでも質問に答えようとしました。現在、公式のcodeplexサイトをセットアップ中です。このサイトには、常に最新のドキュメントがあります。

次に、バンドルをキャッシュからフラッシュする方法に関する特定の問題について説明します。

  1. 要求されたバンドルURLから生成されたキーを使用して、バンドルされた応答をASP.NETキャッシュ内に格納します。つまり、Context.Cache["System.Web.Optimization.Bundle:~/bundles/jquery"]このバンドルの生成に使用されたすべてのファイルとディレクトリに対するキャッシュの依存関係も設定します。したがって、基になるファイルまたはディレクトリのいずれかが変更されると、キャッシュエントリがフラッシュされます。

  2. リクエストごとのBundleTable/BundleCollectionのライブ更新は実際にはサポートされていません。完全にサポートされているシナリオは、アプリの起動時にバンドルが構成されていることです(これにより、Webファームのシナリオですべてが正しく機能します。そうしないと、間違ったサーバーに送信された場合、一部のバンドル要求が404になります)。コード例を見ると、特定のリクエストでバンドルコレクションを動的に変更しようとしていると思いますか?すべてが正しくセットアップされていることを保証するために、あらゆる種類のバンドル管理/再構成には、appdomainのリセットを伴う必要があります。

したがって、アプリドメインをリサイクルせずにバンドル定義を変更することは避けてください。バンドル内の実際のファイルを自由に変更できます。このファイルは自動的に検出され、バンドルURLの新しいハッシュコードが生成されます。

于 2012-09-07T20:24:18.337 に答える
21

同様の問題があります。
私のクラスBundleConfigでは、 を使用した場合の効果を確認しようとしていましたBundleTable.EnableOptimizations = true

public class BundleConfig
{
    public static void RegisterBundles(BundleCollection bundles)
    {
        BundleTable.EnableOptimizations = true;

        bundles.Add(...);
    }
}

すべてが正常に機能していました。
ある時点で、デバッグを行っていて、プロパティを false に設定しました。
jquery のバンドル (最初のもの) が解決されず、ロードされないように見えたため、何が起こっているのか理解するのに苦労しました ( /bundles/jquery?v=)。

いくつかの悪態をついた後、私は(?!)物事を整理することができたと思います. bundles.Clear()登録の最初にandを追加してみるとbundles.ResetAll()、再び機能し始めるはずです。

public class BundleConfig
{
    public static void RegisterBundles(BundleCollection bundles)
    {
        bundles.Clear();
        bundles.ResetAll();

        BundleTable.EnableOptimizations = false;

        bundles.Add(...);
    }
}

EnableOptimizationsプロパティ を変更する場合にのみ、これら 2 つのメソッドを実行する必要があることに気付きました。

アップデート:

さらに深く掘り下げると、バンドルパスを解決するのに問題があることがわかりましBundleTable.Bundles.ResolveBundleUrl@Scripts.Url

簡単にするために、いくつかの画像を追加しました。

画像1

最適化をオフにして、いくつかのスクリプトをバンドルしました。

画像2

本体に同梱されています。

画像3

@Scripts.Urlバンドルの「最適化された」パスを提供し@Scripts.Render、適切なパスを生成します。
で同じことが起こりBundleTable.Bundles.ResolveBundleUrlます。

Visual Studio 2010 + MVC 4 + Framework .Net 4.0 を使用しています。

于 2012-09-07T16:29:15.327 に答える
8

Web ファームのシナリオのためにこれを行わないという Hao Kung の推奨事項を念頭に置いて、これを実行したいシナリオがたくさんあると思います。ここに解決策があります:

BundleTable.Bundles.ResetAll(); //or something more specific if neccesary
var bundle = new Bundle("~/bundles/your-bundle-virtual-path");
//add your includes here or load them in from a config file

//this is where the magic happens
var context = new BundleContext(new HttpContextWrapper(HttpContext.Current), BundleTable.Bundles, bundle.Path);
bundle.UpdateCache(context, bundle.GenerateBundleResponse(context));

BundleTable.Bundles.Add(bundle);

上記のコードはいつでも呼び出すことができ、バンドルが更新されます。これは、EnableOptimizations が true または false の場合の両方で機能します。つまり、これにより、デバッグまたはライブ シナリオで次のように正しいマークアップがスローされます。

@Scripts.Render("~/bundles/your-bundle-virtual-path")
于 2014-11-20T13:05:00.103 に答える
4

また、再構築せずにバンドルを更新すると問題が発生しました。理解しておくべき重要事項は次のとおりです。

  • ファイル パスが変更された場合、バンドルは更新されません。
  • バンドルの仮想パスが変更された場合、バンドルは更新されます。
  • ディスク上のファイルが変更された場合、バンドルは更新されます。

したがって、動的なバンドルを行っている場合は、コードを記述して、バンドルの仮想パスをファイル パスに基づくようにすることができます。ファイル パスをハッシュし、そのハッシュをバンドルの仮想パスの末尾に追加することをお勧めします。このように、ファイル パスが変更されると、仮想パスも変更され、バンドルが更新されます。

私が最終的に問題を解決したコードは次のとおりです。

    public static IHtmlString RenderStyleBundle(string bundlePath, string[] filePaths)
    {
        // Add a hash of the files onto the path to ensure that the filepaths have not changed.
        bundlePath = string.Format("{0}{1}", bundlePath, GetBundleHashForFiles(filePaths));

        var bundleIsRegistered = BundleTable
            .Bundles
            .GetRegisteredBundles()
            .Where(bundle => bundle.Path == bundlePath)
            .Any();

        if(!bundleIsRegistered)
        {
            var bundle = new StyleBundle(bundlePath);
            bundle.Include(filePaths);
            BundleTable.Bundles.Add(bundle);
        }

        return Styles.Render(bundlePath);
    }

    static string GetBundleHashForFiles(IEnumerable<string> filePaths)
    {
        // Create a unique hash for this set of files
        var aggregatedPaths = filePaths.Aggregate((pathString, next) => pathString + next);
        var Md5 = MD5.Create();
        var encodedPaths = Encoding.UTF8.GetBytes(aggregatedPaths);
        var hash = Md5.ComputeHash(encodedPaths);
        var bundlePath = hash.Aggregate(string.Empty, (hashString, next) => string.Format("{0}{1:x2}", hashString, next));
        return bundlePath;
    }
于 2015-11-04T16:54:17.003 に答える
3

StyleBundleまたはScriptBundle)から派生させ、コンストラクターに包含を追加せずにオーバーライドしようとしましたか

public override IEnumerable<System.IO.FileInfo> EnumerateFiles(BundleContext context)

私はこれをダイナミック スタイル シートに対して行い、リクエストごとに EnumerateFiles が呼び出されます。それはおそらく最大の解決策ではありませんが、うまくいきます。

于 2012-11-13T16:45:43.213 に答える