MVC4 में कैश्ड स्क्रिप्ट बंडलों को फ्लश करने के लिए बंडलकॉलशन को कैसे बाध्य करें


85

... या मैंने चिंता करना कैसे बंद कर दिया और Microsoft से पूरी तरह से अनजाने एपीआई के खिलाफ कोड लिखना सीख लिया । क्या आधिकारिक System.Web.Optimizationरिलीज का कोई वास्तविक दस्तावेज है ? 'cuz मुझे यकीन है कि कोई भी नहीं मिल सकता है, कोई XML डॉक्स नहीं है, और सभी ब्लॉग पोस्ट आरसी एपीआई को संदर्भित करते हैं जो काफी अलग है। Anyhoo ..

मैं जावास्क्रिप्ट निर्भरता को स्वचालित रूप से हल करने के लिए कुछ कोड लिख रहा हूं और उन निर्भरताओं से मक्खी पर बंडल बना रहा हूं। सब कुछ बहुत अच्छा काम करता है, सिवाय इसके कि यदि आप स्क्रिप्ट्स को संपादित करते हैं या अन्यथा परिवर्तन करते हैं जो कि एप्लिकेशन को पुनरारंभ किए बिना एक बंडल को प्रभावित करेगा, तो परिवर्तन प्रतिबिंबित नहीं होंगे। इसलिए मैंने विकास में उपयोग के लिए निर्भरता के कैशिंग को अक्षम करने का विकल्प जोड़ा।

हालांकि, जाहिरा तौर 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से लौटाया गया ResolveBundleUrl। "वही" से मेरा मतलब है कि बंडल की नई सामग्री को प्रतिबिंबित करने के लिए सामग्री हैश अपरिवर्तित है।

संपादित करें ... वास्तव में, यह उससे भी बदतर है। बंडल ही किसी भी तरह के बाहर कैश किया गया है Bundlesसंग्रह। यदि मैं केवल स्क्रिप्ट को कैशिंग करने से रोकने के लिए अपना खुद का रैंडम हैश उत्पन्न करता हूं, तो ASP.NET पुरानी स्क्रिप्ट लौटाता है । तो, जाहिरा तौर पर, एक बंडल को हटाने से BundleTable.Bundlesवास्तव में कुछ भी नहीं होता है।

मैं बस इस समस्या के आसपास आने के लिए उपनाम बदल सकता हूं, और यह विकास के लिए ठीक है, लेकिन मुझे यह विचार पसंद नहीं है क्योंकि इसका मतलब है कि या तो मुझे प्रत्येक पृष्ठ लोड के बाद उपनामों को हटाना होगा, या एक बंडलकॉलिनेशन करना होगा जो आकार में बढ़ता है हर पृष्ठ लोड। यदि आपने इसे उत्पादन के माहौल में छोड़ दिया, तो यह एक आपदा होगी।

इसलिए ऐसा लगता है कि जब कोई स्क्रिप्ट परोसी जाती है, तो वह वास्तविक BundleTables.Bundlesवस्तु से स्वतंत्र हो जाती है । इसलिए यदि आप किसी URL का पुनः उपयोग करते हैं, भले ही आपने वह बंडल हटा दिया हो, जिसे उसने पुन: उपयोग करने से पहले संदर्भित किया था, तो यह उसके कैश में जो कुछ भी है, उसका जवाब देता है, और Bundlesऑब्जेक्ट को बदलकर कैश को फ्लश नहीं करता है - इसलिए केवल नए आइटम (या बल्कि, एक अलग नाम के साथ नई वस्तुओं) कभी भी इस्तेमाल किया जाएगा।

व्यवहार अजीब लगता है ... संग्रह से कुछ निकालकर इसे कैश से निकालना चाहिए। लेकिन यह नहीं है। इस कैश को फ्लश करने का एक तरीका होना चाहिए और BundleCollectionजब यह पहली बार एक्सेस किया गया था , तो इसके बजाय यह कैश्ड की वर्तमान सामग्री का उपयोग करेगा ।

किसी भी विचार मैं यह कैसे करूँगा?

यह एक ResetAllविधि है जिसका कोई अज्ञात उद्देश्य है लेकिन यह अभी भी चीजों को तोड़ता है इसलिए ऐसा नहीं है।


यहां भी यही समस्या। मुझे लगता है कि मैं अपना हल निकालने में कामयाब रहा हूं। कोशिश करो और देखो अगर यह तुम्हारे लिए काम करता है। पूर्णतया सहमत। System.Web.Optimization के लिए दस्तावेज़ीकरण बकवास है और इंटरनेट पर आपके द्वारा देखे जा सकने वाले सभी नमूने पुराने हैं।
लेफ्टीएक्स

2
शीर्ष पर महान संदर्भ के लिए +1, विश्वास की एमएस की अपेक्षा के बारे में टिप्पणी के साथ संयुक्त। और यह सवाल पूछने के लिए भी कि मुझे इसका जवाब चाहिए।
रायफ

जवाबों:


33

हम प्रलेखन पर आपके दर्द को सुनते हैं, दुर्भाग्य से यह सुविधा अभी भी काफी तेजी से बदल रही है, और प्रलेखन में कुछ अंतराल है, और लगभग तुरंत पुराना हो सकता है। रिक का ब्लॉग पोस्ट आज तक है, और मैंने इस बीच सवालों का जवाब देने की कोशिश की है और इस बीच वर्तमान जानकारी को फैलाने का प्रयास किया है। वर्तमान में हम अपनी आधिकारिक कोडप्लेक्स साइट स्थापित करने की प्रक्रिया में हैं, जिसमें हमेशा चालू दस्तावेज होंगे।

अब अपने विशिष्ट मुद्दे के संबंध में कैसे बंडल फ्लश कैश बनाते हैं।

  1. हम अनुरोध किए गए बंडल url के एक कुंजी के उपयोग से ASP.NET कैश के अंदर बंडल की गई प्रतिक्रिया को संग्रहीत करते हैं, अर्थात Context.Cache["System.Web.Optimization.Bundle:~/bundles/jquery"]हम इस बंडल को उत्पन्न करने के लिए उपयोग की जाने वाली सभी फ़ाइलों और निर्देशिकाओं के खिलाफ कैश निर्भरता भी सेट करते हैं। इसलिए यदि कोई अंतर्निहित फ़ाइल या निर्देशिका बदल जाती है, तो कैश प्रविष्टि फ्लश हो जाएगी।

  2. हम वास्तव में प्रति अनुरोध के आधार पर बंडलटेबल / बंडलकॉलिनेशन के लाइव अपडेट का समर्थन नहीं करते हैं। पूरी तरह से समर्थित परिदृश्य यह है कि बंडल को ऐप स्टार्ट के दौरान कॉन्फ़िगर किया गया है (यह सब कुछ वेब फ़ार्म परिदृश्य में ठीक से काम करता है, अन्यथा कुछ बंडल अनुरोध 404 के गलत सर्वर पर भेजे जाने पर समाप्त हो जाएंगे)। आपके कोड उदाहरण को देखते हुए, मेरा अनुमान है कि आप किसी विशेष अनुरोध पर बंडल संग्रह को गतिशील रूप से संशोधित करने का प्रयास कर रहे हैं? किसी भी प्रकार के बंडल प्रशासन / पुनर्निधारण के लिए सब कुछ सही ढंग से सेटअप होने की गारंटी देने के लिए एक एपडोमेन रीसेट के साथ होना चाहिए।

इसलिए अपने ऐप डोमेन को रिसाइकिल किए बिना अपनी बंडल परिभाषाओं को संशोधित करने से बचें। आप अपने बंडलों के अंदर वास्तविक फाइलों को संशोधित करने के लिए स्वतंत्र हैं, जो कि स्वचालित रूप से पता लगाया जाना चाहिए और आपके बंडल के लिए नए हैशकोड उत्पन्न करेगा।


2
यहाँ पर सहन करने के लिए अपने प्रत्यक्ष ज्ञान को लाने के लिए धन्यवाद! हां - मैं बंडल संग्रह को गतिशील रूप से संशोधित करने का प्रयास कर रहा हूं। बंडल एक अन्य स्क्रिप्ट में वर्णित निर्भरता के एक सेट के आधार पर बनाया गया है (जो कि, स्वयं, जरूरी नहीं कि बंडल का हिस्सा है) - यही कारण है कि मुझे यह समस्या हो रही है। एक स्क्रिप्ट को बदलने के बाद से एक बंडल में एक फ्लश के लिए मजबूर किया जाएगा, यह किया जा सकता है - क्या मैनुअल फ्लश विधि को जोड़ने की संभावना है? यह महत्वपूर्ण नहीं है - यह विकास के दौरान सुविधा के लिए है - लेकिन मुझे ऐसे कोड बनाने से नफरत है जो अगर गलती से उत्पादों पर उपयोग किए जाते हैं तो समस्या पैदा कर सकते हैं।
जॅमी ट्रूवेरी

क्या आप वेब फार्म के मुद्दे पर भी विस्तार से बता सकते हैं? आवेदन शुरू होने के बाद एक नया बंडल जोड़ना होगा जिसके परिणामस्वरूप यह केवल उस सर्वर पर उपलब्ध होगा जिस पर इसे बनाया गया था - या केवल एक मौजूदा एक को बदलने की कोशिश कर रहा है? यह निर्भरता के रनटाइम रिज़ॉल्यूशन करने की आवश्यकता के बाद से मैं जो भी करने की कोशिश कर रहा हूं, उसके लिए थोड़ा सौदा होगा।
जेमी ट्रैवेरी

ज़रूर, हम एक स्पष्ट कैश फ्लश समकक्ष विधि जोड़ सकते हैं, यह पहले से ही आंतरिक रूप से है। वेब फ़ार्म मुद्दे के बारे में, मूल रूप से कल्पना करें कि आपके पास दो वेबसर्वर ए और बी हैं, आपका अनुरोध ए को जाता है जो बंडल जोड़ता है, और प्रतिक्रिया भेजता है, आपका क्लाइंट अब बंडल की सामग्री लाने के लिए जाता है, लेकिन अनुरोध को छोड़ देता है सर्वर B जिसने बंडल पंजीकृत नहीं किया है, और आपका 404 है।
हाओ कुंग

1
कैश अपडेट आलसी है, पहली बार बंडल का उपयोग किया जाता है (आमतौर पर बंडल के संदर्भ के माध्यम से), इसे कैश में जोड़ा जाता है। यदि आपके पास एक समान एप्लिकेशन प्रारंभ हुक है, जहां आप अनुरोधों को संभालने से पहले सभी वेबसर्वरों पर अपने बंडल सेट करते हैं, तो यह ठीक होना चाहिए।
हाओ कुंग

2
जहाँ तक मैं बता सकता हूँ यह काम नहीं करता है। यदि मैं घटक फ़ाइल को बदल देता हूं, तो सर्वर कैश को यहां बताए अनुसार साफ नहीं किया जाता है। आपको वहाँ से कोई भी परिवर्तन प्राप्त करने के लिए इस चीज़ को रीसायकल करना होगा। किसी को भी पता है कि वास्तव में आधिकारिक दस्तावेज कहां है?
philw

21

मुझे भी इसी तरह की समस्या है।
अपनी कक्षा में BundleConfigमैं यह देखने की कोशिश कर रहा था कि उपयोग का क्या प्रभाव है BundleTable.EnableOptimizations = true

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

        bundles.Add(...);
    }
}

सब कुछ ठीक चल रहा था।
कुछ बिंदु पर मैं कुछ डिबगिंग कर रहा था और संपत्ति को झूठे के लिए निर्धारित किया था।
मैं यह समझने के लिए संघर्ष कर रहा था कि क्या हो रहा था क्योंकि ऐसा लग रहा था कि jquery के लिए बंडल (पहले वाला) हल नहीं होगा और लोड किया जाएगा ( /bundles/jquery?v=)।

कुछ शपथ ग्रहण के बाद मुझे लगता है कि (!) मैं चीजों को छांटने में कामयाब रहा हूं। जोड़ने के लिए प्रयास करें bundles.Clear()और bundles.ResetAll()पंजीकरण और चीजों की शुरुआत में फिर से काम करने के लिए शुरू करना चाहिए।

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

        BundleTable.EnableOptimizations = false;

        bundles.Add(...);
    }
}

मुझे एहसास हुआ कि मुझे इन दो तरीकों को चलाने की आवश्यकता है जब मैं EnableOptimizationsसंपत्ति को बदल दूंगा।

अपडेट करें:

गहरी खुदाई से मुझे पता चला है कि BundleTable.Bundles.ResolveBundleUrlऔर @Scripts.Urlबंडल पथ को हल करने के लिए समस्याएँ हैं।

सरलता के लिए मैंने कुछ चित्र जोड़े हैं:

छवि 1

मैंने अनुकूलन बंद कर दिया है और कुछ स्क्रिप्ट्स को बंडल किया है।

चित्र 2

उसी बंडल को शरीर में शामिल किया गया है।

छवि 3

@Scripts.Urlमुझे बंडल का "अनुकूलित" पथ देता है जबकि @Scripts.Renderउचित बनाता है।
एक ही बात के साथ होता है BundleTable.Bundles.ResolveBundleUrl

मैं विजुअल स्टूडियो 2010 + MVC 4 + फ्रेमवर्क .net 4.0 का उपयोग कर रहा हूं।


हम्म ... बात यह है कि मैं वास्तव में बंडल टेबल को खाली नहीं करना चाहता, क्योंकि इसमें विभिन्न पृष्ठों (निर्भरता के विभिन्न सेटों से निर्मित) के बहुत सारे अन्य शामिल होंगे। लेकिन चूंकि यह वास्तव में सिर्फ विकास के माहौल में काम करने के लिए है, मुझे लगता है कि मैं इसकी सामग्री की नकल कर सकता हूं, फिर इसे साफ कर सकता हूं, फिर उन्हें फिर से जोड़ सकता हूं, अगर यह कैश को फ्लश करेगा। भयावह रूप से अक्षम है लेकिन अगर यह काम करता है, तो यह देव के लिए काफी अच्छा है।
जेमी ट्रेवेरी

सहमत हूं लेकिन मेरे पास एकमात्र विकल्प है। मैंने पूरी दोपहर यह समझने में बिताई कि समस्या क्या थी।
लेफ्टीएक्स

2
मैं सिर्फ यह कोशिश की, अभी भी कैश फ्लश नहीं !! मैंने इसे स्पष्ट कर दिया है, ResetAllऔर EnableOptimizationsजब मैंने कैश को रीसेट करने की आवश्यकता होती है, तो स्टार्टअप और इनलाइन दोनों पर गलत करने की कोशिश की है , कुछ भी नहीं हो रहा है। अरे।
जेमी ट्रूवेरी

यकीन है कि अच्छा होगा अगर डेवलपर इन वस्तुओं में तरीकों के बारे में एक-लाइनर के साथ एक त्वरित ब्लॉग पोस्ट को भी बंद कर सकता है :)
जेमी ट्रेवेरी

6
तो बस ये समझाने के लिए कि ये तरीके क्या करते हैं: Scripts.Url सिर्फ बंडल के लिए एक उपनाम है। Bundles.ResolveBundleUrl, यह भी गैर बंडल उरोलों को हल करेगा, इसलिए इसका एक सामान्य url रिसोल है जो बंडलों के बारे में जानने के लिए होता है। स्क्रिप्ट। रेंडर बंडलों के संदर्भ, या बंडल बनाने वाले घटकों को प्रस्तुत करने के लिए निर्धारित करने के लिए EnableOptimifications ध्वज का उपयोग करता है।
हाओ कुंग

8

वेब फार्म परिदृश्यों के कारण ऐसा नहीं करने के लिए हाओ कुंग की सिफारिशों को ध्यान में रखते हुए, मुझे लगता है कि बहुत सारे परिदृश्य हैं जहां आप ऐसा करना चाहते हैं। यहाँ एक समाधान है:

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);

आप किसी भी समय उपरोक्त कोड को कॉल कर सकते हैं और आपके बंडल अपडेट हो जाएंगे। यह तब काम करता है जब EnableOptimifications सही या गलत है - दूसरे शब्दों में, यह डिबग या लाइव परिदृश्यों में सही मार्कअप को बाहर निकाल देगा:

@Scripts.Render("~/bundles/your-bundle-virtual-path")

यहाँ आगे पढ़ते हैं जो कैचिंग के बारे में थोड़ी बात करता है औरGenerateBundleResponse
Zac

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;
    }

मैं आमतौर पर Aggregateस्ट्रिंग संघनन के लिए परहेज करने की सलाह देता हूं , किसी के जोखिम के कारण जो बार-बार उपयोग करने में अंतर्निहित स्केमियल पेंटर के एल्गोरिदम के बारे में नहीं सोचता है +। इसके बजाय, बस करो string.Join("", filePaths)। इससे उस समस्या को बहुत बड़े इनपुट के लिए भी नहीं होगा।
एरिक

3

क्या आपने अपने कंस्ट्रक्टर और फिर ओवरराइडिंग में कोई समावेश नहीं करते हुए ( स्टाइलबंडल या स्क्रिप्टबंडल ) से व्युत्पन्न करने की कोशिश की है

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

मैं गतिशील स्टाइल शीट के लिए ऐसा करता हूं और EnumerateFiles को हर अनुरोध पर बुलाया जाता है। यह शायद सबसे बड़ा समाधान नहीं है लेकिन यह काम करता है।


0

एक मृत धागे को पुनर्जीवित करने के लिए क्षमा याचना, हालांकि मैं एक Umbraco साइट में बंडल कैशिंग के साथ एक समान मुद्दे पर भाग गया, जहां मैं चाहता था कि जब उपयोगकर्ता बैकएंड में सुंदर संस्करण बदल जाए तो मैं अपने आप को स्टाइलशीट / स्क्रिप्ट को स्वचालित रूप से छोटा कर दूं।

कोड जो मेरे पास पहले से था (स्टाइलशीट के लिए ऑनस्वर्ड विधि में):

 BundleTable.Bundles.Add(new StyleBundle("~/bundles/styles.min.css").Include(
                           "~/css/main.css"
                        ));

और (onApplicationStarted):

BundleTable.EnableOptimizations = true;

कोई फर्क नहीं पड़ता कि मैंने क्या कोशिश की, "~ / बंडलों / शैलियों.min.css" फ़ाइल को बदलने के लिए प्रतीत नहीं हुआ। मेरे पृष्ठ के प्रमुख में, मैं मूल रूप से स्टाइलशीट में लोड कर रहा था जैसे:

<link rel="stylesheet" href="~/bundles/styles.min.css" />

हालाँकि, मुझे इसे बदलकर काम करना पड़ा:

@Styles.Render("~/bundles/styles.min.css")

Styles.Render विधि फ़ाइल नाम के अंत में एक क्वेरी स्ट्रिंग में खींचती है, जो मैं अनुमान लगा रहा हूं कि कैश द्वारा ऊपर वर्णित कैश कुंजी है।

मेरे लिए, यह उतना ही सरल था। आशा है कि यह मेरी तरह किसी और की मदद करता है जो घंटों तक इसे भूल रहा था और केवल कई साल पुरानी पोस्ट पा सकता था!

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.