Solution pour la gestion et la génération automatique de ressources statiques et dynamiques dans une application Web.


Le projet est téléchargeable ici.


Bonjour à tous,

Aujourd'hui face à l'accessibilité d'internet , les applications se doivent de toucher une clientèle de plus en plus large, cela passe par l'internationalisation des applications et donc la necessité de créer des applications "World-Ready".

Ce terme d'internationalisation au niveau architecture et développement se traduit par la gestion et la mise en place de ressources spécifiques à un public ciblé (Français, Anglais, Allemand, Chinois etc...). 

Prenons le cas d'un site Web, étant donné qu'il s'agit du type d'application à internationaliser par excellence.

Je vais vous expliquer comment gérer et  générer facilement les fichiers ressources d'un site Web, nous nous limiterons aux ressources textuelles afin d'en faire une application Web "World-ready".

1. Externaliser les ressources d'une application Web.

Lorsque vous développez un site Web, vous avez une alternative possible sur la gestion des ressources dans Visual Studio 2005, soit les fichiers ressources seront définis pour le périmètre global de l'application ou soit vous préférez définir une ressource locale applicable sur une partie du projet (juste un répertoire)

Selon que vous optez pour la globalisation ou la spécification des ressources, vous devez créer dans votre application Web deux types de répertoires (ASP.NET Folder) respectivement App_GlobalResources ou App_LocalResources:

Dans notre cas , nous partirons du choix de la globalisation des ressources, ceci afin de rendre la maintenance plus aisée notamment par programmation.

Remarque : Un projet WebSite dans Visual Studio 2005 ne permet pas de générer les ressources dynamiquement car celles-ci sont compilées en DLL nommée : App_GlobalResources.dll se trouvant dans le répertoire "bin" de votre site Web.
Pour cela Microsoft à fournit le service pack 1 de Visual Studio 2005 prenant en charge le projet "Application Web" celui-ci permet de conserver le répertoire App_GlobalResources dans le site déployé et d'éviter cette compilation lors du Publish.

Si vous désirez avoir la possibilité de générer dynamiquement vos ressources pendant que votre site se trouve en production, il vous faut utiliser un projet de type "Application Web ASP.NET" au lieu du projet Web Site ( voir Remarque ci-dessus) plus d'information sont disponible ici, si vous désirez migrer votre WebSite en une Application Web.

Je ne m'étendrai pas sur la façon d'utiliser les ressources dans une application Web, je pense que suffisament de cours sont disponibles sur le net, voir ici par exemple.
Mais plus particulièrement sur la façon de mettre en place une solution afin de générer dynamiquement ces ressources dans une application Web.

Si vous avez déjà travaillé sur une application Web, vous avez dû être confronté à une problématique au niveau des ressources, la necessité de devoir gérer deux types de ressources :

  • Les ressources statiques, celles qui restent indépendantes des événements et du comportement de l'utilisateur (titre d'une page, logo, label)
  • Les ressources dynamiques, celles qui sont construites dynamiquement par concaténation ou provenant d'une base de données.

D'une part, les ressources statiques peuvent être gérées facilement à l'aide de fichier resource ASP.NET dans notre répertoire App_GlobalResources.
D'autre part, les ressources dynamiques doivent être gérées à un niveau plus bas, impliquant le niveau métier et la base de données.

Voici une solution permettant de gérer facilement vos ressources dynamiques dans votre code, je partirai de la couche base de données afin de vous faire bien comprendre l'abstraction des ressources.

2. Une solution pour la gestion de ressource dynamique

2.1. Ressources au niveau base de données

L'internationalisation de notre application Web implique la nécessité de prendre en charge plusieurs cultures.
Selon la culture utilisée par l'utilisateur, les ressources dynamiques doivent s'adapter et s'afficher dans la culture choisie.

Pour cela, il est impératif de dissocier dans une resource dynamique son identifiant et son contenu. En effet, une ressource dynamique pourra avoir différent contenu en fonction de la culture appliquée. Voici comment je schématise cela dans ma base de données: 

2.2. Ressources disponibles au niveau métier

Une fois les ressources dynamiques implémentées en base, nous avons besoin de les rendre disponible dans la couche métier de notre site.

En effet, notre couche métier va uniquement utiliser des codes de ressources et aucune traduction en dur. A partir de cette hypothèse, deux choix sont possibles :

  • Soit utiliser une classe qui fait un appel à la table PORTAL_Translation pour chaque traduction (trop lourd)
  • Soit utiliser une zone de stockage, contenant le dictionnaire des ressources dynamiques définit en base, partagé par l'ensemble des utilisateurs et accessible par chaque couche métier de votre site.

Je garderai donc la deuxième solution. Pour cela, j'utiliserai le pattern Singleton dans une couche partagée, afin de stocker l'ensemble des ressources dynamiques correspondant à la culture de l'utilisateur se connectant, si celles-ci ne sont pas dèja chargées.

Ainsi les couches de mon portail Web auront accès constamment à une classe Singleton dans une couche partagée qui contiendra autant de dictionnaires de ressources dynamiques HashTable<resourceCode,resourceLabel> que de culture existante.

Ma classe Singleton PortalResourcesTranslater possédera une méthode  :
/// <summary> ///
Initializes the object PortalResourcesTranslater with the dictionnary of dynamic data in the table PORTAL_Translation
/// </summary>
/// <param name="referentialDictionnary">Hashtable which represents the referential Code/Label for the user culture in database</param> public static void Initialize(Hashtable referentialDictionnary, CultureInfo cultureToInitialize)

laquelle sera appellée à chaque connection d'un utilisateur afin de charger le dictionnaire des ressources dynamiques correspondant à sa culture si celui-ci n'est pas déja chargé.

Par exemple, si à l'instant T, un anglais, un français et un allemand se connecte au portail, le singleton chargera 3 dictionnaires correspondant aux ressources dynamiques anglaise, française et allemande et les maintiendra en mémoire même lorsqu'un de ces utilisateurs se déconnectera.

Une méthode Reset() permettant de supprimer la liste des dictionnaires chargés dans le Singleton sera utilisé lors de la génération des ressources que nous verrons dans la prochaine partie ci-dessous.

Lorsque une traduction devra se faire dans le code, il suffira d'appeller PortalResourcesTranslater par l'intermédiaire de la méthode statique :

public static string Translate(string code)

Cette méthode traduira automatiquement le code par la traduction définit en base à l'aide du dictionnaire préalablement chargé:

Dans votre code métier, vous pourrez utiliser la syntaxe suivante sans vous soucier de la culture :

this._label = PortalResourcesTranslater.Translate(labelResourceKey);

Cette technique permet de gérer automatiquement les ressources statiques au niveau des fichiers ressources ASP.NET et les ressources dynamiques au niveau métier et base de données.

2. Une solution pour la génération automatique des ressources statiques et dynamiques d'un site Web

Le souci lorsque l'on possède des ressources statiques et dynamiques au niveau d'un site web est qu'il n'existe pas d'outil dans Visual Studio qui permette rapidement de les mettre à jour.

La seule possibilité si vous devez définir 10 cultures différentes est d'ouvrir les 10 fichiers ".resx" afin d'entrer vos traductions statiques en environnement de production, et également d'effectuer des scripts afin d'ajouter les ressources dynamiques en base de production.

De plus, il faut savoir qu'un changement dans des fichiers situés dans le répertoire App_GlobalResources impliquera un redémarrage de votre Site Web par IIS. Par conséquent, il vous faut externaliser le stockage des variables sessions, c'est à dire ne pas utiliser le SessionState en mode "InProc".

Pour résoudre cette problématique, voici une des solutions que vous pouvez envisager :

  1. Créer un projet de type "Web application ASP.NET" ceci afin d'avoir la possibilité d'accéder aux propriétés complètes des fichiers ressources :

  2. Choisir la valeur "Content" concernant la propriété Build Action de vos fichiers ressources, ceci afin qu'ils soient copiés tel quel dans votre site publié.Tout autre choix compilera vos fichiers ressources en DLL comme dans un projet WebSite, ceci rendant leur modification en environnement de production plus difficile. 
  3. Dans votre fichier Web.Config spécifier un SessionState en mode "StateServer"  comme ceci :
    <sessionState mode="StateServer" stateConnectionString="tcpip=127.0.0.1:42424" timeout="20"></sessionState>
  4. Allez dans les services du serveur qui héberge votre site Web et démarrer ce service :

     

  5. Renseignez la chaîne de connection ResourcesConnectionString vers votre base de données dans le web.config:<connectionStrings>
    <
    add name="ResourcesConnectionString" providerName="System.Data.SqlClient" connectionString="Data Source=;Initial Catalog=;User ID=;Password="/>
    </
    connectionStrings>
  6. A présent, votre application Web possède des fichiers ressources facilement modifiable et une indépendance entre les variables sessions et le processus IIS. Nous pouvons donc définir un outil d'administration afin de gérer vos fichiers ressources sans impact majeur sur votre site Web de production.
J'ai donc décidé de créer un outil permettant la génération automatique de resources dynamiques et statiques.
Afin de l'incorporer dans votre application Web, il vous suffit d'ajouter dans une partie "Administration" accessible uniquement par l'administrateur de votre site, la page "default.aspx" définit dans mon projet ainsi que la structure métier et d'éxécuter les scripts définient dans le fichier "scriptResourceTool.sql".

Le métier de cet outil à été pensé selon le pattern Abstract Factory vous permettant par la suite d'ajouter la gestion d'autre type de resources selon vos besoins tel que fichier image etc.. Je me limiterai donc au ressources textuelles pour le moment.



Voici donc le fonctionnement de cette application:

Grâce à cette interface, les ressources se trouvant en base ainsi que les resources globales du site Web sont accessibles.
La liste des resourceId et leurs traductions respectives sont affichés sous forme de référentiel. Les resourceId en rouge signifient que des traductions les conçernant sont manquantes dans certaine culture.  
Vous avez donc la possibilité de piloter vos ressources automatiquement depuis cettte page d'administration.

Lorsque vous modifiez la valeur d'une traduction en base, le simple fait de cliquer sur "Save" la sauvegardera, mais ceci n'assure pas que votre ressource soit mise à jour dans le site.
En effet, comme vu précédemment, la couche métier gérant les traductions peut avoir déjà chargé le dictionnaire de la culture modifié.
Pour forçer donc la mise à jour de l'ensemble des dictionnaires chargés, il vous suffit de cliquer sur le lien "Refresh database resources" en haut à droite àprès la mise à jour de toutes vos ressources en base.

Ceci forcera le rechargement de l'ensemble des dictionnaires dans votre site en production, tout cela sans vous obliger de passer par des scripts rébarbatifs.

Concernant les resources statiques qualifiées ici par le terme "Website Resources", vous devez également effectuer vos modifications de traductions, d'ajout de resourceId, de suppresion de resourceId etc... par l'intermédiaire de l'interface.

Une fois, vos resources statiques mise à jour, lancer la génération des fichiers ".resx" en cliquant sur "Generate resources files".

Les fichiers se trouvant dans le répertoire App_GlobalResources seront automatiquement générés pour chaque culture supportée et spécifié dans la table COMMON_CULTURE de votre base, provoquant le redémarrage de IIS sans conséquence pour vos variables Session étant donnée qu'elles sont désormais externalisées du processus IIS.

Voici une capture d'écran de l'outil d'administration, autant vous dire que je m'en sers constamment depuis sa mise en place, c'est tellement plus sympa d'avoir une console d'administration que devoir s'obliger à passer par des scripts ou de la copie de fichier risquée.

Bonne utilisation !

NetDim.

Publié mercredi 5 décembre 2007 16:19 par NetDim
Classé sous
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


Les 10 derniers blogs postés

- TechDays Paris 2012 : Session pleinière jour 3 par Blog Technique de Romelard Fabrice le 02-09-2012, 11:01

- Mishra Reader : un lecteur RSS très Zune Style en Open Source ! par Cyril Sansus le 02-09-2012, 08:28

- [framework 4] Les Tasks et le Thread UI par Fathi Bellahcene le 02-09-2012, 00:33

- Workflow Foundation 3 a un pied dans la tombe par Blog de Jérémy Jeanson le 02-08-2012, 22:15

- TechDays Paris 2012 : Nouvelles tendances du poste de travail - Bring Your own PC par Blog Technique de Romelard Fabrice le 02-08-2012, 19:42

- TechDays Paris 2012 : System Center Service Manager 2012 Vue d’ensemble par Blog Technique de Romelard Fabrice le 02-08-2012, 17:32

- TechDays Paris 2012 : Pleinière second jour par Blog Technique de Romelard Fabrice le 02-08-2012, 16:23

- TechDays Paris 2012 : Retour d'expérience sur la mise en place d'un Cloud Privé par Blog Technique de Romelard Fabrice le 02-08-2012, 16:04

- TechDays Paris 2012 : Comment SharePoint a sauvé mes TechDays par Blog Technique de Romelard Fabrice le 02-07-2012, 23:59

- Perspective 3.0 pour Silverlight 5.0 par Perspective le 02-07-2012, 22:39