Réduisez le trafic dans les formulaires Web ASP.NET, les div cliquables et les interrogations périodiques du serveur

La technologie ASP.NET Web Forms appartient lentement mais sûrement au passé. Il est remplacé par une API Web avec Angular 6 et des piles similaires. Mais j'ai hérité d'un projet sur les formulaires Web avec un énorme héritage. J'ai des amis qui ont une situation similaire à plus ou moins. Des applications écrites sur les anciennes technologies qui doivent être développées et maintenues. Les formulaires Web ont la possibilité sur PostBack de ne pas actualiser la page entière, mais seulement une partie. Ce qui est enveloppé dans UpdatePanel. Cela ajoute de l'interactivité, mais cela fonctionne encore assez lentement et consomme beaucoup de trafic, car Le rendu se produit à chaque fois sur le serveur et le client reçoit un balisage prêt à l'emploi qui doit être inséré à la place du div actuel à l'intérieur. Soit dit en passant, UpdatePanel est simplement rendu dans une div, dans laquelle le balisage est alors remplacé.

Que peut-on faire pour minimiser le trafic?

  1. Écrivez WebMethod sur la page et appelez-le depuis le client à l'aide des outils AJAX, lorsque vous recevez une réponse, changez le DOM via JS.

    L'inconvénient de cette solution est que vous ne pouvez pas définir WebMethod en contrôle. Je ne veux pas écrire toutes les fonctionnalités sur la page, surtout si elle est utilisée plusieurs fois sur différentes pages.
  2. Écrivez un service asmx et appelez-le depuis le client. C'est mieux, mais dans ce cas il n'y a pas de lien explicite entre le contrôle et le service. Le nombre de services augmentera avec l'augmentation du nombre de contrôles. De plus, ViewState ne sera pas disponible pour nous, ce qui signifie que nous passerons les paramètres explicitement lors de l'accès au service, nous ferons donc la validation du serveur et vérifierons si l'utilisateur a le droit de faire ce qu'il a demandé.
  3. Utilisez l'interface ICallbackEventHandler. C'est, à mon avis, une assez bonne option.

    Je m'y attarderai plus en détail.

La première chose à faire est d'hériter de notre UserControl de ICallbackEventHandler et d'écrire les méthodes RaiseCallbackEvent et GetCallbackResult. Il est un peu étrange qu'il y en ait 2. Le premier est responsable de la réception des paramètres du client, le second est responsable du retour du résultat.
Cela ressemblera à quelque chose comme ça

public partial class SomeControl : UserControl, ICallbackEventHandler { #region  /// <summary> ///    /// </summary> private Guid _someFileId; #endregion #region  ICallbackEventHandler /// <inheritdoc /> public void RaiseCallbackEvent(string eventArgument) { //    try { dynamic args = JsonConvert.DeserializeObject<dynamic>(eventArgument); _someFileId = (Guid) args.SomeFileId; string type = (string) args.Type; } catch (Exception exc) { //  throw; } } /// <inheritdoc /> public string GetCallbackResult() { //  try { // -  return JsonConvert.SerializeObject(new { Action = actionName, FileId = _someFileId, }); } catch (Exception exc) { //  throw; } } #endregion } 

C'était du côté serveur. Maintenant client

 var SomeControl = { _successCallbackHandler: function (responseData) { let data = JSON.parse(responseData); switch (data.Action) { case "continue": // -   break; case "success": //  -  break; case "fail": //   break; default: //   alert,     alert("      "); break; } }, _failCallbackHandler: function() { alert("      "); }, } 

Ce n'est pas tout. Nous devons encore générer JS pour connecter toutes nos fonctions.

  protected override void OnLoad(EventArgs e) { base.OnLoad(e); //   SomeControl.js,     Page.ClientScript.RegisterClientScriptInclude(Page.GetType(), "SomeControl", "/Scripts/controls/SomeControl.js?v=2.24.0"); string callbackArgument = //   //***  .***   JS   SomeControl  CallServer.       ,     ScriptManager.RegisterStartupScript(Page, Page.GetType(), "SomeControl.Initialize", $@"SomeControl.CallServer = function(someFileId) {{ let args = JSON.stringify({{ SomeFileId : someFileId, Type: '{callbackArgument}' }}); {Page.ClientScript.GetCallbackEventReference(this, "args", "SomeControl._successCallbackHandler", string.Empty, "SomeControl._failCallbackHandler", true)}; }};", true); //    ScriptManager.GetCurrent(Page)?.RegisterAsyncPostBackControl(this); } 

C'est évidemment le code derrière le contrôle.

La chose la plus intéressante est la génération de fonctions JS à l'aide de la méthode GetCallbackEventReference.

On y passe

  • lien vers notre contrôle
  • le nom de la variable JS dont la valeur sera transmise au serveur dans la méthode RaiseCallbackEvent via eventArgument (la ligne ci-dessus sérialise l'objet en JSON pour la transmission et définit réellement la valeur de cette variable args)
  • Nom de rappel de la fonction JS pour réussir
  • contexte d'exécution (je ne l'utilise pas)
  • le nom de la fonction de rappel JS en cas de problème
  • nous validerons la demande envoyée au serveur à l'aide des outils ASP.NET

Comment tout cela fonctionnera-t-il ensemble?

À partir de JS, nous pouvons appeler SomeControl.CallServer, cette fonction créera une variable locale args et transférera le contrôle à une fonction qui fera une demande au serveur via AJAX.
Ensuite, le contrôle est passé à la méthode serveur RaiseCallbackEvent. Tout ce qui était dans la variable client args est maintenant tombé dans le paramètre d'entrée du serveur eventArgument.
Une fois le RaiseCallbackEvent exécuté, le contrôle sera transmis à GetCallbackResult.

La chaîne que nous retournerons via return sera envoyée au client et tombera dans le paramètre d'entrée de la fonction SomeControl._successCallbackHandler, c'est-à-dire dans responseData.
Si à un moment donné le code du serveur lève une exception, le contrôle sera transféré au client SomeControl._failCallbackHandler

Encore faut-il parler de ViewState. ViewState est transféré du client vers le serveur, et il peut être utilisé, mais uniquement en mode ReadOnly, comme ViewState n'est pas renvoyé au client.

Le design est déroutant à première vue, mais si vous regardez, il s'avère assez pratique et le trafic a été économisé.

La deuxième question que je veux aborder dans cet article concerne les divisions cliquables ou comment vous pouvez appeler la mise à jour UpdatePanel depuis le côté client.

Pourquoi des divs cliquables sont nécessaires, pouvez-vous simplement utiliser <asp: Button>?
J'aime que le div puisse être composé comme je veux, je ne suis pas limité par le type d'entrée = "bouton"

Pour l'implémentation, il est nécessaire d'être hérité de l'interface IPostBackEventHandler

Il n'a qu'une seule méthode

 public void RaisePostBackEvent(string eventArgument) 

Maintenant, comme dans le cas précédent, nous devons générer JS pour appeler cette méthode

Ça ressemble à ça

 Page.ClientScript.GetPostBackEventReference(this, callbackArgument) 

callbackArgument est défini sur le serveur et sa modification sur le client ne fonctionnera pas. Mais vous pouvez toujours mettre quelque chose dans un HiddenField. Nous avons un PostBack complet

Maintenant, le résultat de GetPostBackEventReference peut être suspendu sur le onclick de n'importe quel div ou span, ou autre.

Ou appelez simplement de JS par minuterie.

Assurez-vous d'enregistrer le contrôle comme asynchrone (sur OnLoad, nous appelons

 ScriptManager.GetCurrent(Page)?.RegisterAsyncPostBackControl(this); 
), sinon, même à l'intérieur du UpdatePanel, le PostBack synchrone sera appelé et la page entière sera mise à jour, et pas seulement le contenu du UpdatePanel

En utilisant les 2 méthodes décrites ci-dessus, j'ai implémenté, par exemple, un tel scénario.

L'utilisateur a cliqué sur le bouton, une petite demande pour une opération longue (10-15 secondes) a été envoyée au serveur, l'utilisateur a reçu une réponse courte, au cours de l'analyse de laquelle le script client appelle setTimeout. Dans setTimeout, une fonction est passée pour un rappel au serveur afin de connaître les résultats d'une opération précédemment demandée. Si le résultat est prêt, appelez PostBack dans UpdatePanel - le UpdatePanel spécifié est mis à jour. Si le résultat n'est pas encore prêt, appelez à nouveau setTimeout.

Bonne chance à tous ceux qui travaillent encore avec les formulaires Web, j'espère que l'article rendra vos systèmes plus rapides et plus beaux, et les utilisateurs vous en remercieront.

Source: https://habr.com/ru/post/fr427291/


All Articles