L'art de l'État, partie 1 : Introduction à l'État client en Mendix

Passer au contenu principal

L'art de l'État, partie 1 : Introduction à l'État client

L’un des changements majeurs dans Mendix 7 a été l'introduction de l'exécution sans état, où l'état a été déplacé de l'exécution vers le client. Mendix 7, le client garde désormais une trace de l'état et l'envoie au runtime avec les requêtes du navigateur et de l'application mobile. Cette fonctionnalité permet au runtime de s'adapter horizontalement, offrant une immense flexibilité lorsqu'une application a besoin de plus de ressources serveur.

Dans la première partie de cette série de blogs, nous allons parcourir une application pour vous montrer ce qui se passe du point de vue de l'état à chaque étape afin que vous puissiez mieux comprendre le fonctionnement de l'état client.

Avis de non-responsabilité : cet article de blog s'applique à Mendix 7.23.1. Le comportement de l'état peut différer dans les versions précédentes et peut être modifié sans préavis dans les versions ultérieures.

Qu’est-ce que l’État et que contient-il réellement ?

En tant qu'utilisateur d'un Mendix app, certaines des données avec lesquelles vous travaillez peuvent ne pas encore être stockées dans la base de données. Pour être précis, l'état se compose de :

  • Tous les objets persistants (PE) nouvellement créés et non encore validés
  • Tous les objets non persistants (NPE)
  • Toutes les modifications d'attributs et d'associations apportées aux objets (les associations et les attributs sont traités de la même manière dans le client, les associations ne seront donc pas mentionnées pour le reste de cet article)

Ces objets et modifications constituent l'état. Comme ils ne sont pas encore stockés dans la base de données de votre application, vous devez les stocker dans l'état jusqu'à ce qu'ils soient stockés dans la base de données, supprimés ou qu'ils ne soient plus nécessaires dans l'application.

Les modifications de l’État peuvent être introduites de différentes manières :

  • Un nouvel objet peut être créé par un microflux dans l'environnement d'exécution, un nanoflux dans le client ou par une action client Créer un objet
  • Un changement d'attribut peut être effectué par un microflux, un nanoflux, un widget personnalisé ou par l'utilisateur final

Du point de vue de l'état, la source de l'objet ou du changement n'a pas d'importance. Tous les objets et les changements finissent dans l'état client.

L'état peut contenir plus d'objets que ceux décrits précédemment. Parfois, l'état contient même des objets validés. Cela est souvent fait pour augmenter les performances d'une application.

Qu’est-ce qu’un changement et comment est-il stocké dans l’État ?

Les modifications font référence aux valeurs non validées de Mendix attributs des objets. Par exemple, lorsqu'un utilisateur modifie la valeur d'un attribut à l'aide d'une zone de texte, Mendix stocke la nouvelle valeur en tant que modification de l'état de l'objet modifié. Mendix l'objet lui-même n'est pas encore modifié.

Garder les changements séparés de Mendix objets rend les restaurations possibles. Chaque fois que vous restaurez un Mendix objet dans un microflow, un nanoflow ou avec une action client d'annulation des modifications, Mendix supprime simplement toutes les modifications apportées à l'objet dans l'état.

Cela signifie que chaque fois qu'un utilisateur clique sur un bouton Enregistrer, Mendix collecte et envoie toutes les modifications apportées à l'objet modifié afin que ces modifications puissent être enregistrées dans la base de données de l'environnement d'exécution. Cela est également vrai pour d'autres demandes d'exécution qui nécessitent un objet modifié, comme les appels de microflow.

Portée de l'État

Avec Mendix 7, l'état est stocké dans la mémoire d'un navigateur par le Mendix Client. Cela signifie que pour les applications Web, l'état est local à l'onglet actuel du navigateur. Si vous ouvrez votre application dans un onglet séparé, vous ne pourrez pas accéder à l'état de l'onglet précédent. Cela signifie également que l'actualisation de l'onglet actuel du navigateur entraînera la perte de son état.

Il existe une exception au dernier cas. Mendix Le client stocke votre état dans le stockage de session du navigateur momentanément pour notre fonctionnalité de déploiement rapide. Cela vous permet de continuer à travailler dans votre application à partir de la page ou de l'état dans lequel vous vous trouviez lorsque vous avez apporté des modifications à votre modèle, puis de l'exécuter. Cette fonctionnalité n'est disponible que pendant le développement.

Les deux comportements ci-dessus sont nouveaux pour Mendix 7 et sont incompatibles avec les applications intégrées Mendix 6 et avant. Dans Mendix 6, l'état est toujours accessible à partir de différents onglets et survivra aux actualisations.

État et sécurité

Le stockage de l'état sur le client a certaines ramifications en matière de sécurité :

Attributs en lecture seule pour l'utilisateur actuel Mendix protège les valeurs d'attribut en lecture seule pour un utilisateur actuel avec un hachage à côté de ces valeurs, de sorte que toute tentative de modification illégale de ces valeurs est détectée et refusée.

Modifications des attributs inaccessibles pour l'utilisateur actuel Les modifications apportées aux attributs auxquels l'utilisateur connecté n'a pas accès ne peuvent pas être stockées dans l'état. Leur envoi au client risque de divulguer des données confidentielles. Ces modifications sont donc rejetées.

Comment l’état est-il communiqué au moteur d’exécution ?

Le Mendix Le client communique avec l'environnement d'exécution via un point de terminaison spécial /xas, par exemple lors du chargement de données pour une grille de données ou de l'appel d'un microflux. Chaque type d'appel à cette API est appelé une action et les parties nécessaires de l'état sont envoyées avec elle. Vous pouvez inspecter xas demandes dans le Réseau onglet des outils de développement de votre navigateur et filtrage des requêtes vers le xas chemin. Nous visiterons xas API plus tard dans l'article.

Avis de non-responsabilité : xas est une API privée entre le Mendix Client et runtime et susceptibles d'être modifiés dans les prochaines versions sans préavis. Les détails fournis ici visent à améliorer la compréhension de la manière dont Mendix les applications communiquent avec l'environnement d'exécution afin que vous puissiez modéliser de meilleures applications et résoudre les problèmes d'application plus efficacement.

Chaque fois qu'un xas une action (comme un appel de microflux) est déclenchée, Mendix Le client envoie également l'état. Mendix Le client n’envoie pas l’intégralité de l’état à l’environnement d’exécution, car cela créerait des problèmes de performances majeurs. Mendix décide quelles parties de l'état doivent être envoyées en analysant chaque microflux lors du déploiement des applications.

Puis-je inspecter l’état du client ?

En appuyant sur la Ctrl+Alt+G La combinaison de touches affiche un résumé de l'état du client sur la console du navigateur à ce moment-là, afin que vous puissiez inspecter ce qui est stocké. Nous utiliserons ce raccourci pour inspecter notre exemple d'application.

L'application du registre des œuvres d'art

Pour démontrer l’état du client, j’ai créé une application de registre d’œuvres d’art simple où les informations sur les artistes peuvent être stockées.

Vous pouvez télécharger le projet ici et inspecter l’état au fur et à mesure que nous le traversons.

Voici notre modèle de domaine simple. Il y a un Artiste entité avec un Nom complet attribuer.graphique HD

Exécutons notre application. La page d'accueil est volontairement vide, afin que le Mendix Le client démarre avec un état vide.

capture d'écran

Nous pouvons le vérifier en ouvrant Console dans les outils de développement et en appuyant sur le bouton Ctrl + Alt + G raccourci.

capture d'écran

Ici, vous pouvez voir que l’état est représenté comme un objet JSON, mais il est actuellement vide.

Cliquez sur Artistes élément de menu. Il s'agit ici d'une liste de tous les artistes définis dans l'application. Actuellement, il n'y en a aucun.

capture d'écran

Créez un nouvel artiste en cliquant sur le Créer un nouvel artiste bouton et inspectez ce qui se passe dans le Réseau onglet des outils de développement. Sélectionnez la première requête dans le xas/ chemin et faites défiler vers le bas sur le En-têtes onglet dans la vue détaillée :

capture d'écran

Extrayez la charge utile de la requête et inspectez :

Switch to "Text" tab and paste code here

Ci-dessus, vous voyez un exemple typique xas demande. Passons en revue chaque champ :

  • action:Nous avons mentionné que toutes les opérations d'exécution passent par un xas API, donc chaque opération doit être distincte. Ici, le action Le champ sert à cet effet. L'action en cours est instantiate, qui demande au runtime de créer un Mendix objet.
  • params: Chaque xas l'action peut avoir son propre ensemble de paramètres, donc params contiennent les paramètres spécifiques à l'action. Pour un instantiate appel, le runtime doit savoir quel type d'objet créer, il est donc transmis dans le objecttype champ.
  • changes: Il s'agit de l'un des champs liés à l'état du client. Chaque fois qu'un xas la demande est faite, la Mendix Le client envoie l’état pertinent avec la demande et changes fait partie de cet état. Comme la création d'un nouvel objet ne nécessite aucun état, il est ici vide.
  • objects: Il s'agit du deuxième champ lié à l'état du client. Ici, le Mendix Le client fournit des objets à partir de l'état dont l'environnement d'exécution peut avoir besoin pendant la requête. Étant donné que la création d'un nouvel objet ne nécessite aucun état d'objet, il est également vide.

Vérifiez la réponse en sélectionnant le Aperçu onglet dans le Réseau vue détaillée de la demande :

capture d'écran

Lors de l'examen des détails, je vais ignorer les captures d'écran des outils de développement et simplement montrer les versions extraites :


{
  "actionResult": "5629499534213124",
  "commits": [],
  "changes": {},
  "resets": {},
  "deletes": [],
  "newpersistable": [
    "5629499534213124"
  ],
  "objects": [
  {
    "objectType": "MyFirstModule.Artist",
    "guid": "5629499534213124",
    "hash": "Nw09VTjCQKib7DbE5Agxgm3Bg6fEGL4mPRyNrgiUKGs=",
    "attributes": {
      "FullName": {
        "value": null
        }
      }
    }
  ]
}

Ci-dessus, vous voyez un exemple typique xas réponse. La actionResult le champ est directement lié à l'action elle-même, mais les autres champs sont liés à l'état du client.

Après chaque appel au xas, la réponse d'exécution conserve des informations sur ce qui s'est passé pendant la requête, comme les objets qui ont été créés ou supprimés. L'exécution les communique dans chaque réponse au client, afin que le client applique ces modifications à son état.

Voici un aperçu des champs de réponse liés à l’état du client :

Commet

Ce champ contient une liste de GUIDs qui ont été validés lors de la requête. Étant donné que la création elle-même ne valide pas l'objet, il est vide. Il ressemble à ceci lorsqu'il est renseigné :

"commits": ["guid_1", "guid_2", "...guid_n"]

Le Mendix Le client utilise ces informations pour savoir quand un nouvel objet a été validé ou non. De cette façon, il peut mettre à jour l'état du client en conséquence.

Modifications

Ce champ contient un résumé de toutes les modifications apportées à la Mendix objets qui ont été créés pendant la requête. Cela signifie que ces modifications n'ont pas encore été validées, elles doivent donc être stockées dans l'état.

Ce champ n'est pas renseigné dans le instantiate appel, car il n'y a aucun changement pour le nouveau Artist objet encore. Mais si le Artist l'objet avait un microflux d'événement After Create qui modifiait le nom de l'artiste en une valeur par défaut, ce champ aurait ressemblé à ceci :


"changes": {
  "5629499534213124": {
    "FullName": {
      "value": "Value set in the event microflow"
    }
  }
}

Le Mendix Le client prend les modifications ici et les applique à l’état du client.

remet à zéro

Ce champ contient un résumé de toutes les modifications d'attribut annulées pour chaque Mendix objet. Mendix Le client utilise ces informations pour supprimer les modifications existantes de son état. Voici un exemple de ce à quoi ressemblent les réinitialisations :


"resets": {
  "guid_of_the_object": ["attribute_1", "attribute_2"]
}

Les suppressions

Ce champ contient une liste de guides de Mendix objets qui ont été supprimés lors de la demande. Mendix Le client utilise ces informations de suppression pour supprimer les objets correspondants et leurs modifications de l'état. Ce champ est vide dans l'exemple de requête ci-dessus, mais voici un exemple de ce à quoi ressemblent les suppressions :


  "deletes": ["guid_1", "guid_2", "...guid_n"]

Nouveau persistant

Ce champ contient une liste de guides qui ont été créés lors de la demande, donc le Mendix Le client sait qu'ils ne sont pas encore engagés et qu'il doit les conserver aussi longtemps que nécessaire. instantiate appel, il a créé un nouveau Artist objet, mais n'a pas validé. C'est pourquoi nous voyons que son guid fait partie de ce champ.

Objets

Ce champ contient une liste de Mendix objets que l'action d'exécution doit envoyer au client dans le cadre de la réponse. Dans notre exemple, l'exécution envoie la représentation JSON du nouveau Artist objet.

Une typique Mendix l'objet peut avoir les champs suivants :

  • objectType: définit le type d'objet de l'objet.
  • guid: identifiant unique de l'objet.
  • hash:cela garantit que l'ensemble du contenu de l'objet n'est pas altéré.
  • attributes: contient le engagé valeurs pour chaque attribut de l'objet. Pour un nouvel objet, ces valeurs sont égales aux valeurs par défaut des attributs. Veuillez noter que seuls les attributs accessibles à l'utilisateur actuel sont présents.

Revenons à notre application de démonstration après cette brève introduction à xas demande et réponse.

Cliquer sur le nouveau bouton a créé une nouvelle instance de l'entité « Artiste » et le Mendix Le client affiche la page de détails avec le nouvel objet :

capture d'écran

Ici, nous pouvons maintenant utiliser notre raccourci d’inspection d’état (Ctrl+Alt+G) pour voir l'état du client :


{
  "MyFirstModule.Artist": {
    "5629499534213124 (new)": {
      "subscribedWidgets": [
        "MyFirstModule.Artist_NewEdit.dataView1",
        "MyFirstModule.Artist_NewEdit.textBox1",
        null
      ]
    }
  }
}

L'état du client a maintenant le nouveau Mendix objet, et il le représente en ajoutant un (new) préfixe après son guide pour indiquer qu'il n'a pas encore été validé. Il a également un subscribedWidgets champ, qui indique les widgets qui utilisent cet objet. C'est pourquoi cet objet est conservé dans l'état. La dernière entrée est null, ce qui signifie qu'il y a un composant supplémentaire sur la page ou dans le Mendix Client lui-même qui utilise l'objet, mais n'a pas de description.

Changer le nom du nouvel artiste en Pablo Picasso, puis inspectez à nouveau l’état :


{
  "MyFirstModule.Artist": {
    "5629499534213124 (new)": {
      "changes": {
        "FullName": {
          "value": "Pablo Picasso"
          }
        },
        "subscribedWidgets": [
          "MyFirstModule.Artist_NewEdit.dataView1",
          "MyFirstModule.Artist_NewEdit.textBox1",
          null
        ]
      }
    }
  }
}

Cette fois, nous voyons qu'il y a un extra changes champ pour l'objet, où il montre la modification que nous avons apportée à l' FullName champ.

A ce moment, Mendix Le client stocke à la fois la valeur initiale et la valeur modifiée de la FullName champ. Vous pouvez vérifier cela en demandant l'objet depuis la console avec mx.données.obtenir et en comparant les valeurs renvoyées par MxObject.get et MxObject.getOriginalValue méthodes:

capture d'écran

Enregistrez cet artiste en cliquant sur le Save bouton et inspectez la requête qu'il déclenche (certains champs omis pour plus de clarté) :


{
  "action": "commit",
  "params": {
    "guids": [
      "5629499534213124"
    ]
  },
  "changes": {
    "5629499534213124": {
      "FullName": {
        "value": "Pablo Picasso"
      }
    }
  },
  "objects": [{
    "objectType": "MyFirstModule.Artist",
    "guid": "5629499534213124",
    "hash": "31doiDAq6u7/rMnqwWno01jhLkhpeQ+vKU/rI+IQor8=",
    "attributes": {
      "FullName": {
        "value": null
      }
    }
  }]
}

Cette fois, un commit une demande d'action est adressée au runtime, contenant le guid de l'objet à valider dans la base de données dans le params champ. Aussi le changes champ contient le Pablo Picasso changement que nous avons fait, et objects contient l' Mendix objet que nous avons créé plus tôt.

Voici la réponse :


{
  "commits": [
    "5629499534213124"
  ],
  "changes": {},
  "resets": {
    "5629499534213124": [
      "FullName"
    ]
  },
  "deletes": [],
  "newpersistable": [],
  "objects": [{
    "objectType": "MyFirstModule.Artist",
    "guid": "5629499534213124",
    "hash": "31doiDAq6u7/rMnqwWno01jhLkhpeQ+vKU/rI+IQor8=",
    "attributes": {
      "FullName": {
        "value": "Pablo Picasso"
      }
    }
  }]
}

Il n'y a pas de actionResult terrain cette fois-ci, mais il y a beaucoup de changements pour l'état :

  • Le commits le champ contient désormais le guid du système  Artist nous venons de valider, donc l'état client sait qu'il ne s'agit plus d'un nouvel objet.
  • Le resets champ contient le guid du système Artist et mentionne que FullName la modification du champ est supprimée (car elle est désormais validée). Le client peut désormais supprimer cette modification de l'état.

Le objects le champ représente désormais la dernière version de l'objet validé, avec le FullName valeur du champ définie sur Pablo Picasso.

Pourquoi l'exécution renvoie-t-elle à nouveau l'objet validé ?

Le client possède déjà l'objet dans son état et pourrait le réutiliser, alors pourquoi le runtime le renvoie-t-il à nouveau ? Il y a deux raisons :

  • l'objet peut avoir un gestionnaire d'événements qui a encore modifié l'objet
  • l'objet peut avoir un attribut calculé et sa valeur peut avoir changé lors de sa validation

C'est pourquoi le client a besoin des dernières valeurs de l'objet et c'est pourquoi elles sont renvoyées par l'exécution.

Maintenant, votre application ressemble à ceci :

capture d'écran

Si vous inspectez l’état maintenant, vous verrez que Pablo Picasso est toujours dans cet état, car il est utilisé par la vue liste. Mais il y a une petite différence : il n'est plus marqué comme nouveau.


{
  "5629499534213124": {
  "subscribedWidgets": [
    "MyFirstModule.Artist_Overview.listView1",
    "MyFirstModule.Artist_Overview.textBox1"
    ]
  }
}

Le Mendix Le client utilise également l'état du client comme une forme de couche de mise en cache. Lorsqu'un objet est dans l'état et qu'il est nécessaire à un widget, il n'est pas récupéré à nouveau à partir de l'exécution. Cliquez sur le bouton Modifier l'artiste bouton pour « Pablo Picasso » et vérifiez le Réseau onglet de devtools. Vous remarquerez qu'aucun nouveau xas des demandes seront faites pour récupérer Pablo Picasso à partir de l'exécution. Comme il est déjà dans l'état, il n'est pas nécessaire de le demander.

Maintenant, cliquons Annuler sur la page d'édition, accédez à la page d'accueil de notre application en cliquant Accueil élément de menu et vérifiez l'état :


{
  "MyFirstModule.Artist": {
    "5629499534213124": "Going to be garbage collected †"
  }
}

Vérifiez l'état environ 15 secondes plus tard. Vous verrez qu'il est vide.

Mais pourquoi cela?

La réponse à cette question réside dans un nouveau concept : la récupération de place à partir de l'état. Ce mécanisme détecte et supprime les objets inutiles de l'état, de sorte que notre application fonctionne de manière optimale, quel que soit le nombre d'objets que vous créez ou utilisez. Dans notre application, le Pablo Picasso L'objet n'est plus nécessaire depuis que nous avons ouvert la page d'accueil, car aucun widget ne l'affiche. C'est pourquoi il est supprimé de l'état. La collecte des déchets de l'état est un sujet complexe, je vais donc le couvrir dans la deuxième partie de cette série de blogs.

J'espère que vous avez apprécié la lecture de cet article et que vous l'avez trouvé utile. À plus tard pour la partie 2 !

Libérez toutes les capacités de Mendix 7 - Essayez maintenant

Choisissez votre langue