janvier
2009
Il y’a quelque temps, pendant un session de revue de code sur un petit projet, on a fait la constatation suivante:
Sur un certain nombre de fonctions, 70% du code était du code d’accès au fichier de configuration !
Par exemple, pour récupérer le nom du serveur, un port et un nom de liste Sharepoint, on avait ce genre de code:
string server = ConfigurationManager.AppSettings[« ServerName »];
string port = ConfigurationManager.AppSettings[« Port »];
string ListUrl = ConfigurationManager.AppSettings[« ListUrl »];
return string.Format(« {0}:{1}/{2} », server, port, ListUrl);
}
Dans les classes d’accès aux données, on avait:
string connectionString = ConfigurationManager.ConnectionStrings[« MaConnectionString »].ToString();
DataTable dt = new DataTable();
LogFactory.LogDebug(« GetDataTable, request : « + strSql);
?
Et a chaque modification d’un paramètre du web.config, on partait pour une recherche globale de AppSettings[« toto »]…
Pas très DRY, tout ca…
Donc, une idée nous est venue (bonne ou pas, seul l’avenir nous le dira), à savoir faire un wrapper pour notre fichier de configuration. Pour cela, il suffit de creer une classe statique, laquelle va exposer directement n fonctions permettant d?accéder aux propriétés du web.config sans avoir a connaître l’orthographe, de façon plus sure (vérifiée a la compilation), générique, centralisée et, du moins, a notre avis, plus propre.
Cette classe se présente grosso modo comme ca:
private static string GetAppSettings(string key) {
if (ConfigurationManager.AppSettings[key] == null) {
throw new ArgumentException(string.Format(« Missing in AppSettings: {0} », key));
}
return ConfigurationManager.AppSettings[key];
}
private static ConnectionStringSettings GetConnectionStrings(string key) {
if (ConfigurationManager.ConnectionStrings[key] == null) {
throw new ArgumentException(string.Format(« Missing in ConnectionStrings: {0} », key));
}
return ConfigurationManager.ConnectionStrings[key];
}
}
Les fonctions GetAppSettings et GetConnectionStrings permettent de factoriser l’accès aux chaines de connexion ou aux paramètres d’application. Pour chaque paramètre que l’on veut accéder, on va ensuite ajouter une petite fonction qui va appeler, au choix, GetAppSettings ou GetConnectionStrings. Par exemple, on aura, pour une chaine de connexion:
get { return GetConnectionStrings(« MaConnectionString »); }
}
et, pour un paramètre applicatif:
get { return GetAppSettings(« ServerName »); }
}
Voila, en espérant que ca apporte quelque chose a quelqu’un, et n’hésitez pas a laisser un commentaire (je préfère qu’on me dise quand je me plante, plutôt qu’avoir a le découvrir tout seul )
6 Commentaires + Ajouter un commentaire
Articles récents
Archives
- janvier 2014
- septembre 2013
- août 2013
- mai 2013
- avril 2013
- janvier 2013
- août 2012
- juin 2012
- mai 2012
- avril 2012
- mars 2012
- novembre 2011
- septembre 2011
- août 2011
- juillet 2011
- juin 2011
- mai 2011
- avril 2011
- février 2011
- janvier 2011
- novembre 2010
- octobre 2010
- septembre 2010
- août 2010
- juillet 2010
- juin 2010
- mai 2010
- avril 2010
- mars 2010
- février 2010
- janvier 2010
- décembre 2009
- novembre 2009
- octobre 2009
- septembre 2009
- août 2009
- juillet 2009
- juin 2009
- mai 2009
- avril 2009
- mars 2009
- février 2009
- janvier 2009
>C’est déjà ce que fait le wrapper en question, au final, on a une quinzaine d’accesseurs avec les casts et les parse qui vont bien ;)…On a meme des accesseurs qui jouent sur n parametre
Au temps pour moi, effectivement, je n’avais lu la note qu’en diagonale et du coup ça m’a échappé!
Huhu, désolé pour ces précisions inutiles du coup.
Par contre, étant donné que tu factorise la lecture du fichier de configuration, la mise en place de valeur par défaut nécessitera l’absorption de tes exceptions (ArgumentException) si je ne m’abuse.
Ou alors il faudra utiliser autre chose que les fonctions communes.
De ce que je me rappelle, le web.config est conserver en ram après la lecture initiale, donc les perfs ne devraient pas être impactées (en tout cas, pas plus que dans le cas normal de lecture depuis le web.config a chaque accès)
J’ai l’impression qu’on va lire le fichier à chaque fois. D’ou une perte de temps, ne pourrait on pas stocker dans une variable le contenu d’une clé lors de la première lecture puis se servir de la variable ensuite ?
Ce donnerait grosso modo
if (mavariable == null)
{
mavariable = lecture_de_la_cle;
}
return mavariable;
seb.49
Bonjour,
C’est une excellente technique que j’utilise depuis pas mal de temps et il faut avouer que c’est bien pratique J’essaye de le revendre à mes collègues et je constate que de plus en plus de monde l’utilise…
Merci pour cette petite astuce
Alexandre
Euh…
>Effectivement ca fait une classe avec plein d’accesseur, mais rien n’empèche de faire plusieurs classes en séparant les accesseurs par utilité.
C’est déjà ce que fait le wrapper en question, au final, on a une quinzaine d’accesseurs avec les casts et les parse qui vont bien ;)…On a meme des accesseurs qui jouent sur n parametre
-> la fonction GetListUrl, et des accesseurs qui, en fonction de la valeur d’un parametre du Web.Config, renvoient un parametre different
Je savais que j’aurais du copier-coller la classe comme un sauvage
En tout cas, merci pour le commentaire
Pourquoi ne pas faire une classe d’accès à ces informations de configuration?
Par exemple avoir une classe avec des accesseurs, ce qui permet:
– De donner une valeur par défaut en cas d’abscence d’info dans le fichier de config.
– De retourner un objet du type attendu plutôt que toujours une string qu’il faudra caster par la suite.
Ex:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class ConfigurationAccess{ <br />
public string DataBaseConnectionString{ <br />
get { <br />
string connection = ConfigurationManager.ConnectionStrings["ConnectionString"]; <br />
if(string.IsNullOrEmpty(connection)) <br />
return "MaChaineParDefaut"; //ou une exception si tu veux <br />
else <br />
return connection; <br />
} <br />
} <br />
<br />
public DateTime ExpiryDate <br />
{ <br />
get { <br />
DateTime expiry; <br />
if(DateTime.TryParseExact(ConfigurationManager.AppSettings["ExpiryDate"], "YYYYmmdd", CultureInfo.InvariantCulture, DateTimeStyles.None, out expiry)) <br />
return expiry; <br />
<br />
return DateTime.Now; //Default value or Exception <br />
} <br />
} <br />
} <br />
Effectivement ca fait une classe avec plein d’accesseur, mais rien n’empèche de faire plusieurs classes en séparant les accesseurs par utilité.
Une classe pour la configuration des bases de données, une classe pour la configuration du design de l’application, etc…
Bon, ce n’est que mon avis, mais il me semble que cela facilite :
– La maintenance, puisque si tu change le nom de ta clé dans ton fichier de configuration tu n’auras qu’a le modifier dans une seule classe, contrairement à ta technique.
– L’utilisation des données, puisqu’elles sont utilisable directement dans le type que tu souhaites. Un int sera un int et non pas une string que tu devras parser par la suite.
En espérant que ca puisse servir