86 votes

Comment forcer BundleCollection à vider les ensembles de scripts mis en cache dans MVC4

... ou comment j'ai appris à cesser de s'inquiéter et il suffit d'écrire le code contre complètement sans-papiers Api de Microsoft. Est-il réel de la documentation officielle de l' System.Web.Optimization version? car je ne trouve pas, il n'y a pas de docs XML, et tous les articles de blog reportez-vous à la RC de l'API qui est sensiblement différent. Anyhoo..

Je suis en train d'écrire un peu de code pour résoudre automatiquement javascript dépendances et suis à la création d'ensembles à la volée à partir de ces dépendances. Tout fonctionne très bien, sauf si vous modifiez les scripts ou sinon faire des changements qui affectent un bundle sans redémarrage de l'application, les changements ne seront pas pris en compte. J'ai donc ajouté une option pour désactiver la mise en cache des dépendances pour une utilisation dans le développement.

Cependant, apparemment BundleTables caches de l'URL , même si le bundle de la collection a changé. Par exemple, dans mon code, quand je veux re-créer un bundle-je faire quelque chose comme ceci:

// 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"

Chaque fois que je l'ai supprimer et recréer un bundle avec le même alias, absolument rien ne se passe: l' bundleUrl retourné à partir de ResolveBundleUrl est le même qu'avant, que j'ai supprimé et recréé le bundle. Par "le même", je veux dire que le hachage du contenu est inchangé pour refléter le nouveau contenu du bundle.

edit... en fait, c'est bien pire que cela. Le faisceau lui-même est mis en cache en quelque sorte à l'extérieur de l' Bundles de la collecte. Si je générer mon propre aléatoire de hachage pour empêcher le navigateur de mise en cache le script, ASP.NET retourne l'ancien script. Donc, apparemment, la suppression d'un bundle BundleTable.Bundles ne font rien.

Je peux simplement modifier l'alias pour contourner ce problème, et c'est OK pour le développement, mais je n'aime pas cette idée car cela signifie que j'ai à rendre caduque alias après chaque chargement de la page, ou d'avoir une BundleCollection qui grandit à chaque chargement de page. Si vous avez quitté ce dans un environnement de production, ce serait une catastrophe.

Il semble donc que lorsqu'un script est servi, il obtient en cache indépendante de la BundleTables.Bundles objet. Donc, si vous ré-utiliser une URL, même si vous avez supprimé le paquet qu'elle se réfère à avant de le réutiliser, il répond avec tout ce qui est dans son cache, et de la modification de l' Bundles objet n'est pas de vider le cache -- donc, seuls les nouveaux éléments (ou plutôt, de nouveaux éléments avec un nom différent) pourrait jamais être utilisé.

Le comportement semble bizarre... de retirer quelque chose de la collection devrait le supprimer de la mémoire cache. Mais il ne le fait pas. Il doit y avoir un moyen de vider le cache et l'avoir utiliser le contenu actuel de l' BundleCollection au lieu de ce qu'il cache ce bundle a d'abord été consulté.

Une idée de comment je pourrais faire cela?

Il y a cette ResetAll méthode qui a un inconnu but, mais c'est juste casse choses, de toute façon, de sorte que n'est-il pas.

33voto

Hao Kung Points 13035

Nous entendons votre douleur sur la documentation, malheureusement, cette fonctionnalité est encore en pleine évolution très rapide, et la génération de la documentation a un peu de lag, et peuvent être dépassées presque immédiatement. Rick blog est à jour, et j'ai essayé de répondre à des questions ici aussi bien à la propagation actuelle de l'info dans le temps. Nous sommes actuellement dans le processus de mise en place sur notre site de codeplex qui ont toujours actuel de la documentation.

Maintenant en ce qui concerne votre question de comment éliminer les faisceaux de la forme du cache.

  1. Nous stockons groupé à la réponse à l'intérieur de la ASP.NET cache à l'aide d'une clé générée hors de l'ensemble de l'url demandée, c'est à dire Context.Cache["System.Web.Optimization.Bundle:~/bundles/jquery"] nous avons également configurer les dépendances de cache à l'encontre de tous les fichiers et les répertoires qui ont été utilisés pour produire ce pack. Donc si l'un des sous-jacents des fichiers ou des répertoires de changement, l'entrée du cache va se rincé.

  2. Nous n'avons pas vraiment de soutien direct de la mise à jour de la BundleTable/BundleCollection sur demande. Entièrement pris en charge scénario est que les faisceaux sont configurés pendant l'application de début(c'est donc tout fonctionne correctement dans la batterie de serveurs web scénario, sinon quelques regrouper les demandes seraient 404 si envoyé à la mauvaise serveur). En regardant votre exemple de code, je suppose que vous vous tentez de modifier le faisceau de la collection de façon dynamique sur une demande particulière? Tout type de bundle administration/reconfiguration doit être accompagné par un domaine d'application de réinitialisation de garantir tout a été installé correctement.

Afin d'éviter la modification de votre bundle définitions sans recyclage de votre domaine d'application. Vous êtes libre de modifier les fichiers réels à l'intérieur de votre faisceaux, qui devraient être automatiquement détecté et de générer de nouvelles hashcodes pour l'ensemble des url.

21voto

LeftyX Points 9899

J'ai un problème similaire.
Dans ma classe, BundleConfig j'ai essayé de voir quel était l'effet de l'utilisation de BundleTable.EnableOptimizations = true.

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

        bundles.Add(...);
    }
}

Tout fonctionnait bien.
À un certain point, j'ai été faire un peu de débogage et de définir la valeur false à la propriété.
J'ai eu du mal à comprendre ce qui se passait cause, il semble que le module de jquery (le premier) ne serait pas résolu et chargé (/bundles/jquery?v=).

Après quelques jurons, je crois(?!) J'ai réussi à arranger les choses. Essayez d'ajouter bundles.Clear() et bundles.ResetAll() au début de l'enregistrement et les choses devraient commencer à travailler à nouveau.

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

        BundleTable.EnableOptimizations = false;

        bundles.Add(...);
    }
}

J'ai réalisé que j'ai besoin pour l'exécution de ces deux méthodes que lorsque je change l' EnableOptimizations de la propriété.

Mise à JOUR:

Pour aller plus loin j'ai découvert que l' BundleTable.Bundles.ResolveBundleUrl et @Scripts.Url semblent avoir des problèmes pour résoudre le bundle chemin.

Pour des raisons de simplicité, j'ai ajouté quelques images:

image 1

J'ai désactivé l'optimisation et livré quelques scripts.

image 2

Le même bundle est inclus dans le corps.

image 3

@Scripts.Url donne-moi le "optimisé" chemin d'accès de l'ensemble tout en @Scripts.Render génère le bon.
La même chose arrive avec BundleTable.Bundles.ResolveBundleUrl.

Je suis à l'aide de Visual Studio 2010 + MVC 4 + Cadre .Net 4.0.

3voto

tulde23 Points 119

Avez-vous essayé de dériver de ( StyleBundle ou ScriptBundle ), en n’ajoutant aucune inclusion dans votre constructeur, puis en ignorant

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

Je le fais pour les feuilles de style dynamiques et EnumerateFiles est appelée à chaque demande. Ce n'est probablement pas la meilleure solution mais cela fonctionne.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X