• Aucun résultat trouvé

Q UELQUES BONNES PRATIQUES .N ET

Le Framework.Net utilise le modèle provider pour la gestion de l’authentification. Il permet de : - Uniformiser la gestion de l’authentification

- Rendre interchangeable la méthode de connexion par configuration Membership provider

Le Membership provider (fournisseur d’identité) est une classe permettant de manipuler les utilisateurs. Celui-ci doit implémenter la classe abstraite MembershipProvider.

Les trois méthodes principales à définir (pour une application n’ayant pas comme finalité de gérer le référentiel utilisateur) sont :

Dans la méthode Initialize, on peut récupérer les attributs customisés de la configuration dans le paramètre config.

6.3.2 Co n n e c tio n S QL S e rve r

La syntaxe de connexion n’est pas intuitive et nécessite l’assistant ADO.Net pour la générer.

Fig 25 - Assistant de création de la connexion SQL Server

Lors de la construction du modèle, afin de ne pas permettre l’accès direct aux tables, on ne sélectionne que les procédures stockées nécessaires :

6.3.3 P ro fils e t rô le s

6.3.3.1 Rôle provider

Le Rôle provider (fournisseur de rôles) est une classe permettant d’obtenir des informations sur le rôle de l’utilisateur.

Les trois méthodes principales à définir (pour une application n’ayant pas comme finalité de gérer le référentiel utilisateur) sont :

bool ValidateUser(string username, string password)

MembershipUser GetUser(string username, bool userIsOnline) void Initialize(string name, NameValueCollection config)

Dans la méthode Initialize, on peut récupérer les attributs customisés de la configuration dans le paramètre config.

6.3.3.2 Restriction d’accès

La mise en place des droits d’accès à lieu lors de l’accès à l’application. Si l’utilisateur n’a pas les droits, celui-ci sera redirigé vers une page « Accès refusé ».

Documentation de Microsoft : http://msdn.microsoft.com/fr-fr/library/f1kyba5e%28v=vs.100%29.aspx http://msdn.microsoft.com/fr-fr/library/ms227425%28v=vs.100%29.aspx

6.3.4 Le s lo g s

La librairie de logging préconisée pour cet usage est log4net, livrée dans le package des normes CEA.

6.3.4.1 Interface Un logger se déclare comme suit :

Le paramètre à passer à la méthode GetLogger est le type de la classe dans laquelle le « logger » est déclaré.

Pour loguer une ligne, utilisez une des méthodes ayant la signature :

Ces trois signatures illustrent l’utilisation de l’interface ILog et permettent de : - Tracer un message

- Tracer une exception obligatoirement accompagné d’un message - Tracer une chaine complexe

6.3.4.2 Performances

Afin de ne pas dégrader les performances lors de la désactivation des logs, il faut toujours tester si le mode de trace demandé est activé :

En effet, chaque appel ou construction de message à loguer à un coût. Celui-ci n’est pas à négliger, même pour des traces simples.

if (logger.IsDebugEnabled)

{ logger.DebugFormat("GetUser(\"{0}\", {1})", username, userIsOnline);

}

void Debug(object message);

void Debug(object message, Exception exception);

void DebugFormat(string format, params object[] args);

private static readonly ILog logger =

LogManager.GetLogger(typeof(AbstractDaoFactory<T>));

bool IsUserInRole(string username, string roleName) string[] GetRolesForUser(string username)

string[] GetAllRoles()

void Initialize(string name, NameValueCollection config)

6.3.4.3 Configuration

La configuration du logger Log4Net se fait dans le fichier de configuration de l’application.

L’attribut « name » du « logger » doit correspondre au namespace dans lequel est placé le type passé en paramètre lors de la déclaration du logger dans la classe appelante.

Les méthodes présentées existent également pour d’autres niveaux de traces : FATAL, ERROR, WARN, DEBUG, INFO

6.3.5 Le s e xc e p tio n s

6.3.5.1 Hiérarchie

La hiérarchie des exceptions doit se présenter sous la forme suivante :

Fig 26 – Hiérarchie des exceptions

La seule exception du Framework est System.Exception. Toutes les autres doivent être définies dans le projet.

Remarque : La classe« ApplicationException » est dépréciée et ne doit jamais être étendue ni utilisée.

Les seules exceptions du Framework pouvant être levées par un développeur sont : - ArgumentException

- ArgumentNullException - InvalidOperationException

6.3.5.2 Masquage de la pile d’appel et du message

Afin de ne pas révéler d’informations structurantes à un utilisateur, le corps des exceptions doit être masqué.

Pour ce faire, dans un web service, il faut :

<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>

... <log4net>

<appender name="FileAppender" type="log4net.Appender.RollingFileAppender">

<file value="D:\Logs\web.log"/>

<appendToFile value="true" />

<rollingStyle value="Size" />

<maxSizeRollBackups value="10" />

<maximumFileSize value="1000KB" />

<staticLogFileName value="true" />

<layout type="log4net.Layout.ModèleLayout">

<conversionModèle value="%date %level %thread %logger - %message%newline"/>

</layout>

</appender>

<logger name="CEA.Division.Projet">

<level value="DEBUG"/>

<appender-ref ref="FileAppender"/>

</logger>

</log4net>

- Récupérer l’exception - La loguer

- Relancer une nouvelle exception ne contenant pas l’exception précédente.

Dans un site web, il faut :

- Mettre en place une page d’erreur customisée - Tracer l’erreur dans le Global.asax

6.3.5.3 Handler

L’utilisation des EnterpriseLibrary de Microsoft permet sa mise en place par configuration :

Ensuite, dans le code, une gestion de l’exception se fait de la manière suivante.

Le comportement voulu est le suivant : - Couche d’accès aux données

⇒ Toutes les exceptions reçues sont loguées et encapsulées dans une exception technique de l’application qui est relancée

- Couche business

⇒ Toutes les exceptions de types business reçues sont loguées et relancées

⇒ Toutes les exceptions techniques de l’application sont relancées

⇒ Toutes les autres exceptions sont loguées et encapsulées dans une exception technique de l’application et relancée.

Les exceptions techniques sont à tracer au niveau ERROR tandis que les exceptions de type métier sont à tracer au niveau DEBUG.

var result = null;

try { ...

} catch (Exception ex)

{ bool rethrow = ExceptionPolicy.HandleException(ex, "Bll.Policy");

if (rethrow) throw;

} return result;

<exceptionHandling>

<exceptionPolicies>

<add name="BLL.Policy">

<exceptionTypes>

<add type="Functional Exception Type"

postHandlingAction="None|NotifyRethrow|ThrowNewException"

name="Nom de la clause">

</exceptionPolicies>

</exceptionHandling>

Ce chapitre est proposé en tant que best practice. Sa mise en place n’est pas une obligation.

Préférez en général l’utilisation de « throw; » plutôt que « throw ex; » : « throw; » sans paramètre préserve la pile d’appel et maximalise les informations disponible pour débugger. Pour masquer des informations, utilisez plutôt « throw » avec paramètre, voir encapsulez l’exception.

6.3.5.4 Code d’une exception

Afin d’appliquer les best practices toutes les exceptions doivent présenter au minimum les constructeurs suivants. Ceux-ci peuvent être obtenus en utilisant le snippet « Exception ».

Si une exception doit contenir des propriétés supplémentaires, celles-ci doivent systématiquement être en lecture seule. Il ne doit être possible de les assigner que par le constructeur de l’exception.

Toutes les exceptions doivent être sérialisables.

Attention : lors du nommage du namespace contenant les exceptions. Si celui-ci est nommé « Exception », il peut masquer la visibilité de la classe Exception du namespace System. Préférez le nom « Exceptions ».

6.3.6 Le s d o n n é e s p e rs is ta n te s (c a c h e , s e s s io n )

6.3.6.1 Session

La persistance des variables de session s’effectuera la plupart du temps dans une session

« InProc ». C’est-à-dire, lorsqu’il n’y a qu’un serveur d’application ou plusieurs serveurs load balancés avec affinité de session.

Pour les grandes configurations avec un besoin important de variables de session avec plusieurs serveurs load balancés sans affinité de session, .Net propose d’utiliser la session SQL Server. C’est plus lent, mais plus stable : si un serveur .Net tombe, la variable de session est toujours présente.

Pour mettre en place la session SQL Server, aucune modification dans le code n’est nécessaire, la configuration suivante est à mettre en place :

- Création du schéma

L’utilitaire aspnet_regsql est localisé dans le dossier C:\Windows\Microsoft.NET\Framework

\v4.0.30319.

aspnet_regsql -d "Cea.Division.Projet.SessionState" -S (local) -U UserName -P Password -ssadd -sstype c

[Serializable]

public class ProjetException : Exception { public ProjetException() { }

public ProjetException(string message) : base(message) { } public ProjetException(string message, Exception inner) : base(message, inner) { }

protected ProjetException(SerializationInfo info, StreamingContext context) : base(info, context) { }

}

- Configuration de l’application (à mettre en place dans le Web.config)

En cas de load balancing, la même machine key doit être définie dans les

« N » Web.config : https://msdn.microsoft.com/en-us/library/w8h3skw9(v=vs.100).aspx De même, la même arborescence doit être utilisée sur tous les serveurs pour

l’application web.

6.3.6.2 Cache

En cas de besoin de cache, utiliser le cache par défaut du HttpRuntime pour des données

« custom ».

Veillez à toujours utiliser le cache de l’HttpRuntime et non de l’HttpContext.

Le HttpRuntime est toujours disponible, contrairement au HttpContext.

Pour mettre en cache les pages en sortie, il est possible d’utiliser l’attribut OutputCache.

Afin d’avoir une gestion affinée du cache, les différents paramètres de l’attribut sont décrits ici : http://www.asp.net/mvc/tutorials/older- versions/controllers-and-routing/improving-performance-with-output-caching-cs [OutputCache(Duration = 10,

Location = OutputCacheLocation.Client)]

var item = HttpRuntime.Cache["item"];

<sessionstate mode="SQLServer" timeout="20"

allowcustomsqldatabase="true"

sqlconnectionstring="Data Source=Server;

Initial Catalog=Cea.Division.Projet.SessionState;

User ID=UserName;

Password=Password;"

cookieless="false">

Documents relatifs