Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Actualités

  • Blog de Cyril DURAND, passionné de JavaScript, Ajax, ASP.net et tout ce qui touche au developpement Web Client-Side.

    View Cyril Durand's profile on LinkedIn

    hit counters

Regrouper plusieurs fichiers javascript grace au ToolkitScriptManager

Depuis quelques temps déjà, les dernières versions des Ajax Control Toolkit intègre un nouveau contrôle qui hérite du ScriptManager : le ToolkitScriptManager. Ce contrôle permet de combiner plusieurs fichiers JavaScript en un seul. Lorsque vous utilisez plusieurs toolkits sur la même page le client doit télécharger de nombreux fichiers JavaScript ce qui entraine des performances plutôt mauvaise. De plus le ToolkitScriptManager permet de compacter et gzipper les fichiers JavaScript. J'en ai aussi parlé ici : Réduire la taille des fichiers JavaScript

Pour le faire fonctionner, il suffit de remplacer le classique ScriptManager par le ToolkitScriptManager.

<ajaxtoolkit:ToolkitScriptManager runat="server" />

Automatiquement, tous les fichiers JavaScript ajoutés par les toolkits seront combinés en un seul. Par défaut l'url du fichier JavaScript final est :

CurrentPage.aspx?_TSM_HiddenField_=ctl00_SampleContent_ScriptManager1_HiddenField&amp;_TSM_...

Oui ! Vous avez bien lu, le fichier résultat pointe sur la page en cours. Cela implique 2 choses :

  • Dès qu'on change de page, le fichier sera différent, il n'y aura aucun cache client pour ce fichier;
  • La page va être exécutée deux fois : Page_Load, ...

Bref, par défaut le comportement est stupide. Heureusement il est possible de spécifier l'adresse d'un handler qui s'occupera de combiner les différents fichiers.

Voici ce que vous pouvez mettre dans un fichier CombineScriptsHandler.ashx afin d'avoir qu'une seule url pour tout le site.

<%@ WebHandler Language="C#" Class="CombineScriptsHandler" %> // CombineScriptsHandler.ashx using System; using System.Web; using AjaxControlToolkit; public class CombineScriptsHandler : IHttpHandler { /// <summary> /// ProcessRequest implementation outputs the combined script file /// </summary> /// <param name="context"></param> public void ProcessRequest(HttpContext context) { if (!ToolkitScriptManager.OutputCombinedScriptFile(context)) { throw new InvalidOperationException("Combined script file output failed unexpectedly."); } } /// <summary> /// IsReusable implementation returns true since this class is stateless /// </summary> public bool IsReusable { get { return true; } } }

Il vous suffit ensuite de renseigner la propriété CombineScriptHandlerUrl du ToolkitScriptManager

<ajaxToolkit:ToolkitScriptManager runat="server" CombineScriptsHandlerUrl="~/CombineScriptsHandler.ashx" />

Astuce : Si vous avez mis le ScriptManager dans toutes vos pages plutôt qu'uniquement dans le masterpage, vous pouvez utiliser du TagMapping pour remplacer tous les ScriptManager par des ToolkitScriptManager et spécifier la propriété CombineScriptsHandlerUrl au niveau du fichier de skin. Pour en savoir plus sur le TagMapping : TagMapping : comment changer les comportements des controles web en quelques lignes

Le mieux reste bien sur de mettre le ScriptManager au niveau du masterpage et si besoin, se servir d'un ScriptManagerProxy dans vos pages pour ajouter des scripts précis.

Jusque là tout va bien, mais malheureusement le contrôle possède un bug. En effet le ScriptManager permet de rajouter des scripts manuellement, je m'en sers souvent pour utiliser les Animations des toolkits sans devoir passer par le contrôle serveur. Pour cela j'utilise un ScriptReference.

<ajaxtoolkit:ToolkitScriptManager ID="SC1" runat="server" ScriptMode="Release" CombineScriptsHandlerUrl="~/CSScriptHandler.ashx" EnableScriptGlobalization="true" EnableScriptLocalization="true"> <Scripts> <asp:scriptreference assembly="AjaxControlToolkit" name="AjaxControlToolkit.Compat.Timer.Timer.js"/> <asp:scriptreference assembly="AjaxControlToolkit" name="AjaxControlToolkit.Common.Common.js"/> <asp:scriptreference assembly="AjaxControlToolkit" name="AjaxControlToolkit.Animation.Animations.js"/> <asp:scriptreference assembly="AjaxControlToolkit" name="AjaxControlToolkit.ExtenderBase.BaseScripts.js"/> <asp:scriptreference assembly="AjaxControlToolkit" name="AjaxControlToolkit.Animation.AnimationBehavior.js"/> </Scripts> </ajaxtoolkit:ToolkitScriptManager>

Mais malheureusement en faisant comme cela, tous les fichiers ajoutés manuellement seront ajoutés deux fois ! Une fois par le combinaison liée aux contrôles des toolkits et une fois manuellement, cela entraine bien sur de nombreuses erreurs. J'ai signalé le bug ici : ToolkitScriptManager add some script twice when added manually

Pour corriger ce problème il faut modifier le fichier ToolkitScriptManager.cs de la sorte puis recompiler :

/// <summary> /// ADDED : contains a cache with the partial name of an assembly and his full name /// </summary> private static Dictionary<String, String> _assemblyFullName = new Dictionary<string, string>(); /// <summary> /// OnResolveScriptReference override to track combinable scripts and update the script references /// </summary> /// <param name="e">event args</param> protected override void OnResolveScriptReference(ScriptReferenceEventArgs e) { base.OnResolveScriptReference(e); // If combining scripts and this is a candidate script if (_combineScripts && !String.IsNullOrEmpty(e.Script.Assembly) && !String.IsNullOrEmpty(e.Script.Name)) { // Initialize ScriptReference scriptReference = e.Script; // ADDED : get and set the fullname of the assembly if (!_assemblyFullName.ContainsKey(scriptReference.Assembly)) _assemblyFullName[scriptReference.Assembly] = Assembly.Load(scriptReference.Assembly).FullName; scriptReference.Assembly = _assemblyFullName[scriptReference.Assembly]; ScriptEntry scriptEntry = new ScriptEntry(scriptReference); if (IsScriptCombinable(scriptEntry)) { // ADDED : check if there is already a script with the same name and same assembly name if (!_scriptEntries.Exists(delegate(ScriptEntry entry) { if (!String.IsNullOrEmpty(scriptEntry.Assembly)) { return entry.Name == scriptEntry.Name && entry.Assembly == scriptEntry.Assembly; } else { return entry.Name == scriptEntry.Name; } })) { // Haven't seen this script yet; add it to the list and invalidate the Url _scriptEntries.Add(scriptEntry); _combinedScriptUrl = null; } } } }

Pour en savoir plus sur le ToolkitScriptManager :

PS : bizarre à chaque fois que j'utilise un truc des toolkits je tombe sur des bugs et je suis obligé de bidouiller ...

Posted: vendredi 14 septembre 2007 13:44 par cyril
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Commentaires

dapoussin a dit :

Cool, merci pour ce post :)

J'ai rigoureusement suivi toutes les étapes mais mes pages contiennent toujours des liens JavaScript de ce genre : http://localhost/MyWebSite/ScriptResource.axd?d=Ma4urtJwtvwgHLWSkCThZT319JUAM4VJUj0vYs2elQsp-nIiHlVoK--r2zFPG8B6OERsdtBuoozLLYeVdftFCbXR0T8OBnMSIztkdJs_crA1&amp;t=633253790070461602

Pourtant mon site compile avec la nouvelle DLL du Toolkit et j'ai bien remplacé mon ScriptManager par un ToolkitScriptManager dans ma MasterPage. Est-ce que cela pourrait venir de l'utilisation d'un ScriptManagerProxy dans ma page ? Je l'utilise pour ajouter des références à des fichiers JS et des Web Services.

Quand j'analyse le poids des fichiers avec Firebug, j'ai l'impression qu'il n'y a aucun changement entre mon site avec ToolkitScriptManager et sans... aurais-tu une idée ?

Bye

Laurent

# septembre 14, 2007 16:21

cyril a dit :

Bonjour,

Je me suis peut etre mal exprimé : tous les fichier javascript ne seront pas compacté en 1 seul, en effet les proxy de WS, les fichiers que l'on ajoute directement via le path c'est à dire les fichiers qui ne sont pas contenu dans une ressource ainsi que les fichiers natif d'ASP.net ajax seront toujours téléchargés distinctement pour des raisons plus ou moins techniques :p

Mais normalement tu dois avoir un fichier avec un paramètre TSM_HiddenField. Bien sur il faut que tu utilises des controles toolkits pour que cela fonctionne (faut en fait que les scripts soient inclues en WebResource via un attribut qu'on trouve dans les toolkits)

# septembre 14, 2007 17:00

dapoussin a dit :

Bonjour Cyril,

Merci pour ta réponse (désolé pour le délai, je reviens de vacances :p), j'ai bien un TSM_HiddenField dans le HTML, mais sa value est vide. Il faudrait que je regarder en détail ce qui se passe avec ce champ.

Sinon, est-ce que ton hack du Toolkit est contenu dans la version 10920 sortie vendredi (j'ai la flemme de vérifier ^^). Ca serait pratique de revenir à la version officielle.

Bye

Laurent

# septembre 24, 2007 10:45

cyril a dit :

non ...

A croire que les gars des toolkits s'en fichent des corrections de bugs que je leur envoie ...

# septembre 24, 2007 11:03
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Disparition de variables de session PHP après une redirection ? par MadMatt le il y a 9 heures et 45 minutes

- [MOSS 2007] Publier ses formulaires InfoPath via feature par Adrien Siffermann le il y a 12 heures et 52 minutes

- Imagine Cup 2008 - Paris - Les résultats par TheSaib .NET blog le il y a 14 heures et 14 minutes

- L'Egypte accueille Imagine Cup 2009 par Code is poetry le il y a 14 heures et 26 minutes

- PowerShell : Mise en ligne de fonctions intéressantes pour SharePoint par Blog Technique de Romelard Fabrice le il y a 15 heures et 33 minutes

- Raccourcis clavier et CRM 4 par Clark, C#, MSCRM, SBS le il y a 19 heures et 39 minutes

- [Silverlight] Comment échanger des données entre une application Silverlight et une page ASP.NET via cookies ? par Thomas Lebrun le il y a 20 heures et 15 minutes

- SharePoint 2007 : Trouver les fichiers CheckOut dans une librairie de document par Philippe Sentenac [MVP SharePoint] le il y a 22 heures et 43 minutes

- [Open XML] Travailler avec Open XML : Linq To XML (Partie 2 - Requêtes/XPath) par Julien Chable le 07-08-2008, 02:05

- [Open XML] Travailler avec Open XML : Linq To XML (Partie 1 - Namespace) par Julien Chable le 07-08-2008, 00:44