Aki készített már újrafelhasználható elemeket ASP.NET MVC-ben, bizonyára találkozott már azzal a problémával, hogy egy partial view vagy egy HTML helper működéséhez szükséges egy CSS stíluslap vagy egy külső JavaScript fájl. Ha odafigyelünk a kódunk minőségére, akkor a CSS-t mindig az oldal tetején, a szkriptet pedig mindig az oldal alján töltjük be, gondosan ügyelve arra, hogy ezek a külső erőforrások akkor is csak egyszer töltődjenek be az oldalra, ha több helyen is szükség van rájuk. Viszont ezt csöppet sem egyszerű megoldani, hiszen a partial view-k és a HTML helperek teljesen önállóan, egymástól függetlenül renderelődnek. Bár a probléma egyáltalán nem újkeletű, még ASP.NET WebFormsban sem egyszerű megoldani, MVC-ben viszont kifejezetten nehéz.
Talán nem is meglepő, hogy a készre sütött megoldást Peter Blum tálalja nekünk a Content Injector for ASP.NET MVC formájában. Az öreg motoros ASP.NET fejlesztők már sokszor találkozhattak Peter nevével, aki egyszemélyes cégében leginkább ASP.NET web controlokat készít. Ezek közül a legismertebb a Peter’s Data Entry Suite, amely több, mint 100 WebForms vezérlőt tartalmaz, melyek elsősorban az adatbevitelt és a validációt teszik egyszerűbbé. Igen hasznos csomagról van szó, nem véletlenül kapott már értük számos pozitív értékelést.
Így csöppet sem csodálkoztam, amikor pár héttel ezelőtt Peter bukkant fel egy ötlettel az ASPInsiders listán, ami nagyon kényelmesen megoldja a fenti problémát. Sokan kipróbáltuk, kapott is pár visszajelzést, amit villámgyorsan át is vezetett a kódon, így most már bátran merem ajánlani a Content Injector for ASP.NET MVC projektet, leginkább NuGet csomag formájában.
A használata pofonegyszerű. Először is jelöljük meg az oldalunkon, tipikusan a Layout.cshtml fájlban, azokat a helyeket, ahova majd beszúródnak a tartalmak:
@Injector.InjectionPoint("ScriptFiles")
Ezek után ha például egy view-nak szüksége van a jQuery Validate szkript fájljaira, akkor a view-ból szúrjuk be őket a korábban megjelölt helyekre:
@Injector.ScriptFile("~/Scripts/jquery.validate.min.js"); @Injector.ScriptFile("~/Scripts/jquery.validate.unobtrusive.min.js");
Ez persze csak a legegyszerűbb használati eset, meg lehet adni még további paramétereket (például sorrend), valamint beszúrhatunk stíluslapot, szkriptet, meta tag-et, rejtett mezőt, szkript blokkot, vagy bármi mást, hiszen a rendszer jól kiterjeszthető és konfigurálható (például tracing). Minderről elég részletesen tájékoztat a 23 oldalas User’s Guide.
További érdekesség, hogy a visszajelzések alapján Peter összekapcsolta a Content Injectort a Microsoft Web Optimization Frameworkkel, így a ContentInjector.WOF NuGet csomag telepítése után már StyleBundle is ScriptBundle is beszúrható.
Letöltések:
- Content Injector for ASP.NET MVC forráskód és dokumentáció (GitHub)
- Content Injector for ASP.NET MVC NuGet csomag (ContentInjector)
- Content Injector support for Web Optimization Framework forráskód és dokumentáció (GitHub)
- Content Injector support for Web Optimization Framework NuGet csomag (ContentInjector.WOF)
Érdekes, hogy több MVC verzió után jutott ez eszébe valakinek, MVCs “pályafutásom” szinte első lépése volt egy hasonló modul létrehozása, na persze ennyire nem profi, simán a controller injektálja:
MyController.AddScriptReference(“~/…..js”)
MyController.AddCssReference(“~/…..css”)
MyController.AddScriptContent(“var a=1;”)
MyController.AddScriptReadyContent(“alert(‘hello’);”)
MyController.StartSubModuleScript(object) //konvencionálisan a View nevével megyező .js-t injektál és elinditja a “start(object)” nevü fgvt.
( Ez még nincs benne a tárgybeli csomagban, de hamarosan ezt is feltalálja valaki, mert nagymértékben standardizálja a fejlesztést 😉 )
Bár a cucc tényleg jó, de a cikk kezdetén a felvetésed “Ha odafigyelünk a kódunk minőségére, akkor a CSS-t mindig az oldal tetején, a szkriptet pedig mindig az oldal alján töltjük be” így nem teljesen igaz. A CSS-t tényleg jó minél előbb betölteni, hogy ne kelljen újrarenderelni az oldalt, de a Javascript esetében, ha betartod a szabályokat, akkor nem érhet meglepetés, csak a document ready eseménye után szabad bármiben is matatni! Ezt többféleképpen megteheted, én a magam részéről jquery-t használok.
Nem azért kerül a JS az oldal aljára, mert a DOM betöltődéséig nem szabad matatni benne, arra természetesen valóban a document ready a megoldás. Hanem azért, mert amíg a JS töltődik, addig böngésző jelentősen visszavesz a párhuzamosításból, magyarul lassabban töltődik be az oldal, ha a tetejére teszed a JS hivatkozást, mint ha az aljára.
Ez csak az IE esetében van így, vagy minden böngészőnél? Mert én főleg chrome-al fejlesztek és ezt még nem vettem észre, hogy számítana. Ha szétszedem js fájlokra, azokat szépen párhuzamosan felszippantja. Mondjuk egy sima app-nál valószínűleg nem is számít annyira, játékot meg még nem fejlesztettem JS-ben.
Gábor, nem csak a letöltés a probléma, hanem a letöltött JS fájl értelmezése is. Mivel egy sima document.write hívás megváltoztathatja a DOM-ot, ezért minden böngészőnek meg van kötve a keze.
Szia Gyuri! Nem tudom, hogy jó helyen kapizsgálok-e, de lényegében a @section-ok erre is használhatóak, viszont azzal meg az a baj, hogy Partial View-ban nem működik, csak sima View-ban azt hiszem. Te mit gondolsz?
Szia Krisztán! Igen, pont ez a gond, ráadásul klasszikus code fájlban sem működnek.
Pingback: Dinamikusan beincludeolt javascript esete a debuggal | feeldacode